001/*
002 $Id: Role.java 3207 2009-04-09 06:48:11Z gregory $
003
004 Copyright (C) 2006 Gregory Vincic, Olle Mansson
005 Copyright (C) 2007 Gregory Vincic
006
007 This file is part of Proteios.
008 Available at http://www.proteios.org/
009
010 Proteios is free software; you can redistribute it and/or modify it
011 under the terms of the GNU General Public License as published by
012 the Free Software Foundation; either version 2 of the License, or
013 (at your option) any later version.
014
015 Proteios is distributed in the hope that it will be useful, but
016 WITHOUT ANY WARRANTY; without even the implied warranty of
017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
018 General Public License for more details.
019
020 You should have received a copy of the GNU General Public License
021 along with this program; if not, write to the Free Software
022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
023 02111-1307, USA.
024 */
025package org.proteios.core;
026
027import org.proteios.core.data.RoleData;
028import org.proteios.core.query.EntityQuery;
029import org.proteios.core.query.Hql;
030import org.proteios.core.query.Restrictions;
031import java.util.Collections;
032import java.util.Set;
033
034/**
035 * This class is used to represent roles. A role is used in the permission
036 * system to give users access to various parts of Proteios. A permission given
037 * to a role is global, ie. it applies to all items of a spcific type on the
038 * entire server, and not only within a group or project. For example it is
039 * possible to give <code>READ</code> access to all <code>SAMPLE</code>:s,
040 * no matter if the owner has shared them to other users or not.
041 * <p>
042 * Proteios comes with a predefined set of roles, for example
043 * {@link #ADMINISTRATOR} and {@link #GUEST}, which have been configured with
044 * what we think is an appropriate combination of privileges. If you wish, you
045 * may create more roles. Use roles only for functional grouping of the users,
046 * and not for organisational grouping. If you wish to do that you should use a
047 * {@link Group} or {@link Project} instead.
048 * 
049 * @author Nicklas
050 * @version 2.0
051 * @see Group
052 * @see Project
053 * @see <a
054 *      href="../../../../../../specifications/core/defaultpermissions.html">Default
055 *      permissions</a>
056 * @base.modified $Date: 2009-04-09 08:48:11 +0200 (Thu, 09 Apr 2009) $
057 */
058public class Role
059                extends BasicItem<RoleData>
060                implements Nameable, Removable, SystemItem
061{
062        /**
063         * The type of item represented by this class.
064         * 
065         * @see Item#ROLE
066         * @see #getType()
067         */
068        public static final Item TYPE = Item.ROLE;
069        /**
070         * The id for the <code>Role</code> item representing adminstrators. By
071         * default administrators have full privileges on the server.
072         */
073        public static final String ADMINISTRATOR = "org.proteios.core.Role.ADMINISTRATOR";
074        /**
075         * The id for the <code>Role</code> item representing supervisors. A
076         * supervisor have READ permission to everything in Proteios.
077         */
078        public static final String SUPERVISOR = "org.proteios.core.Role.SUPERVISOR";
079        /**
080         * The id for the <code>Role</code> item representing power users. A power
081         * user have less permissions than an administrator but may do some things
082         * that an ordinary user may not.
083         */
084        public static final String POWER_USER = "org.proteios.core.Role.POWER_USER";
085        /**
086         * The id for the <code>Role</code> item representing regular users. This
087         * role should be sufficient for most regular users of Proteios.
088         */
089        public static final String USER = "org.proteios.core.Role.USER";
090        /**
091         * The id for the <code>Role</code> item representing guests. Guests have
092         * very limited access to the server.
093         */
094        public static final String GUEST = "org.proteios.core.Role.GUEST";
095        /**
096         * This filter will limit a query to only return roles where the logged in
097         * user is a member unless the logged in user has generic read permission.
098         */
099        private static final QueryRuntimeFilter RUNTIME_FILTER = new QueryRuntimeFilterImpl();
100
101
102        /**
103         * Get a <code>Role</code> item when you know the ID.
104         * 
105         * @param dc The <code>DbControl</code> which will be used for permission
106         *        checking and database access.
107         * @param id The ID of the item to load
108         * @return The <code>Role</code> item
109         * @throws ItemNotFoundException If an item with the specified ID is not
110         *         found
111         * @throws PermissionDeniedException If the logged in user doesn't have
112         *         {@link Permission#READ} permission to the item
113         * @throws BaseException If there is another error
114         */
115        public static Role getById(DbControl dc, int id)
116                        throws ItemNotFoundException, PermissionDeniedException,
117                        BaseException
118        {
119                Role r = dc.loadItem(Role.class, id);
120                if (r == null)
121                        throw new ItemNotFoundException("Role[id=" + id + "]");
122                return r;
123        }
124
125
126        /**
127         * Get a {@link ItemQuery} object configured to retrieve <code>Role</code>
128         * items. If the logged in user doesn't have generic permission to all
129         * roles, only roles where that user is a member are included in the list.
130         * 
131         * @return A {@link ItemQuery} object
132         */
133        public static ItemQuery<Role> getQuery()
134        {
135                return new ItemQuery<Role>(Role.class, RUNTIME_FILTER);
136        }
137
138
139        Role(RoleData roleData)
140        {
141                super(roleData);
142        }
143
144
145        /*
146         * From the Identifiable interface
147         * -------------------------------------------
148         */
149        public Item getType()
150        {
151                return TYPE;
152        }
153
154
155        // -------------------------------------------
156        /*
157         * From the Nameable interface -------------------------------------------
158         */
159        public String getName()
160        {
161                return getData().getName();
162        }
163
164
165        public void setName(String name)
166                        throws PermissionDeniedException, InvalidDataException
167        {
168                checkPermission(Permission.WRITE);
169                NameableUtil.setName(getData(), name);
170        }
171
172
173        public String getDescription()
174        {
175                return getData().getDescription();
176        }
177
178
179        public void setDescription(String description)
180                        throws PermissionDeniedException, InvalidDataException
181        {
182                checkPermission(Permission.WRITE);
183                NameableUtil.setDescription(getData(), description);
184        }
185
186
187        // -------------------------------------------
188        /*
189         * From the Removable interface -------------------------------------------
190         */
191        public boolean isRemoved()
192        {
193                return getData().isRemoved();
194        }
195
196
197        public void setRemoved(boolean removed)
198                        throws PermissionDeniedException
199        {
200                checkPermission(removed ? Permission.DELETE : Permission.WRITE);
201                getData().setRemoved(removed);
202        }
203
204
205        // -------------------------------------------
206        /*
207         * From the SystemItem interface -------------------------------------------
208         */
209        public String getSystemId()
210        {
211                return getData().getSystemId();
212        }
213
214
215        public boolean isSystemItem()
216        {
217                return getSystemId() != null;
218        }
219
220
221        // -------------------------------------------
222        /*
223         * From the BasicItem class -------------------------------------------
224         */
225        /**
226         * Always return FALSE. A role can be referenced from users and role keys
227         * but those references are automatically deleted if the role is deleted and
228         * aren't inclued in this check.
229         */
230        @Override
231        public boolean isUsed()
232                        throws BaseException
233        {
234                return false;
235        }
236
237
238        /**
239         * If the logged in user is a member of this role, read permission is
240         * granted. If this is a system role, delete and create permissions are
241         * revoked.
242         */
243        @Override
244        void initPermissions(int granted, int denied)
245                        throws BaseException
246        {
247                if (isSystemItem())
248                {
249                        denied |= Permission.deny(Permission.DELETE, Permission.CREATE);
250                }
251                if (getSessionControl().isMemberOf(this))
252                {
253                        granted |= Permission.grant(Permission.READ);
254                }
255                super.initPermissions(granted, denied);
256        }
257
258
259        // -------------------------------------------
260        /**
261         * Assign this <code>Role</code> to a user.
262         * 
263         * @param user The user to be assigned this role
264         * @throws PermissionDeniedException If the logged in user doesn't have
265         *         {@link Permission#WRITE} permission for the role and
266         *         {@link Permission#USE} permission for the user
267         * @throws InvalidDataException If the user is null
268         */
269        public void addUser(User user)
270                        throws PermissionDeniedException, InvalidDataException
271        {
272                checkPermission(Permission.WRITE);
273                if (user == null)
274                        throw new InvalidUseOfNullException("user");
275                user.checkPermission(Permission.USE);
276                getData().getUsers().add(user.getData());
277        }
278
279
280        /**
281         * Revoke this <code>Role</code> from a user.
282         * 
283         * @param user The user that should be removed from this role
284         * @throws PermissionDeniedException If the logged in user doesn't have
285         *         {@link Permission#WRITE} permission for the role and
286         *         {@link Permission#USE} permission for the user
287         * @throws InvalidDataException If the user is null
288         */
289        public void removeUser(User user)
290                        throws PermissionDeniedException, InvalidDataException
291        {
292                checkPermission(Permission.WRITE);
293                if (user == null)
294                        throw new InvalidUseOfNullException("user");
295                user.checkPermission(Permission.USE);
296                getData().getUsers().remove(user.getData());
297        }
298
299
300        /**
301         * Check if the given user is member of this role or not.
302         * 
303         * @param user The user to check
304         * @return TRUE if the user is member, FALSE otherwise
305         */
306        public boolean isMember(User user)
307        {
308                return getData().getUsers().contains(user.getData());
309        }
310
311
312        /**
313         * Get a query that returns the users that are members of this role. This
314         * query excludes users that the logged in user doesn't have permission to
315         * read.
316         * 
317         * @see User#getQuery()
318         */
319        public ItemQuery<User> getUsers()
320        {
321                ItemQuery<User> query = User.getQuery();
322                query.joinPermanent(Hql.innerJoin("roles", Item.ROLE.getAlias()));
323                query.restrictPermanent(Restrictions.eq(
324                        Hql.alias(Item.ROLE.getAlias()), Hql.entity(this)));
325                return query;
326        }
327
328        /**
329         * A runtime filter implementation that limits a query to only return roles
330         * where the logged in user is a member unless the logged in user has
331         * generic read permission.
332         */
333        private static class QueryRuntimeFilterImpl
334                        implements QueryRuntimeFilter
335        {
336                public void enableFilters(QueryRuntimeFilterManager manager,
337                                EntityQuery query, DbControl dc)
338                {
339                        SessionControl sc = dc.getSessionControl();
340                        if (!sc.hasPermission(Permission.READ, Item.ROLE))
341                        {
342                                if (sc.isLoggedIn())
343                                {
344                                        // Load roles where the logged in user is a member
345                                        org.hibernate.Filter filter = manager
346                                                .enableFilter("memberOf");
347                                        if (filter != null)
348                                        {
349                                                Set<Integer> roles = sc.getRoles();
350                                                if (roles == null || roles.size() == 0)
351                                                        roles = Collections.singleton(0);
352                                                filter.setParameterList("items", roles);
353                                                filter.setParameter("owner", sc.getLoggedInUserId());
354                                        }
355                                }
356                                else
357                                {
358                                        // Do not load any roles if not logged in
359                                        manager.enableFilter("denyAll");
360                                }
361                        }
362                }
363        }
364}