View Javadoc

1   /***
2    * Subject.java
3    *
4    * This file is part of the creme library.
5    * The creme library intends to ease the development effort of large
6    * applications by providing easy to use support classes.
7    *
8    * Copyright (C) 2003 Denis Bregeon
9    *
10   * This library is free software; you can redistribute it and/or
11   * modify it under the terms of the GNU Lesser General Public
12   * License as published by the Free Software Foundation; either
13   * version 2.1 of the License, or (at your option) any later version.
14   *
15   * This library is distributed in the hope that it will be useful,
16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18   * Lesser General Public License for more details.
19   *
20   * You should have received a copy of the GNU Lesser General Public
21   * License along with this library; if not, write to the Free Software
22   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23   *
24   * contact information: dbregeon@sourceforge.net
25   */
26  package org.jcreme.permissioning;
27  
28  import java.util.Hashtable;
29  import java.util.Vector;
30  
31  import org.jcreme.enumerations.Enumeration;
32  
33  /***
34   * 
35   * @author $Author: dbregeon $
36   * @version $Revision: 1.1 $
37   */
38  public abstract class Subject extends Enumeration {
39      protected static final Hashtable fromName = new Hashtable();
40  
41      /***
42       * The leaf task that is solved by the Subject.
43       */
44      protected Task task = null;
45  
46      /***
47       * The Domain to which the Subject belongs.
48       */
49      protected Domain domain = null;
50  
51      protected Subject(String name) {
52          super(name);
53      }
54  
55      /*
56       * (non-Javadoc)
57       * 
58       * @see org.jcreme.enumerations.Enumeration#getFromName()
59       */
60      protected Hashtable getFromName() {
61          return fromName;
62      }
63  
64      public void setDomain(Domain d) {
65          this.domain = d;
66      }
67  
68      public Domain getDomain() {
69          return this.domain;
70      }
71  
72      public void setTask(Task t) throws IllegalArgumentException {
73          if ((t != null) && (!t.isLeaf())) {
74              throw new IllegalArgumentException("Task has to be a Leaf.");
75          }
76          this.task = t;
77      }
78  
79      public static Subject[] getSubjects() {
80          return (Subject[]) fromName.values().toArray(new Subject[0]);
81      }
82  
83      public static Enumeration[] getValues() {
84          return (Enumeration[]) fromName.values().toArray(new Enumeration[0]);
85      }
86  
87      /***
88       * @param u
89       * @param t
90       *            is set by the invocation path. It is otherwise impossible to
91       *            determine a Task that will give a single meaningful business
92       *            Purpose.
93       * @param parameters
94       * @param accessTypes
95       * @throws NoPermissionException
96       * @throws IllegalArgumentException
97       */
98      protected void checkParameters(User u, Task t, Object[] parameters,
99              AccessType[] accessTypes) throws NoPermissionException,
100             IllegalArgumentException {
101         if (u == null) {
102             throw new IllegalArgumentException("Null is not a valid User.");
103         }
104         if (t == null) {
105             throw new IllegalArgumentException("Null is not a valid Task.");
106         }
107         if ((parameters == null) || (accessTypes == null)
108                 || (parameters.length != accessTypes.length)) {
109             throw new IllegalArgumentException(
110                     "accessTyprs and parameters array are not of the same size or are null.");
111         }
112         if (!checkTask(t)) {
113             throw new NoPermissionException(
114                     "Subject's Task is not a child of the invoking Task " + t);
115         }
116         if (!checkRoles(u, t)) {
117             throw new NoPermissionException("User " + u
118                     + " has no Role to perform Task " + t);
119         }
120         PoliciedObject object = null;
121         for (int i = 0; i < parameters.length; i++) {
122             if (parameters[i] instanceof PoliciedObject) {
123                 object = (PoliciedObject) parameters[i];
124                 if (!checkAccess(object.getObjectType(), accessTypes[i])) {
125                     throw new NoPermissionException("User " + u
126                             + " has no permission to access data of type "
127                             + object.getObjectType());
128                 }
129                 if (!checkPurpose(u, t, object.getObjectPolicy(),
130                         accessTypes[i])) {
131                     throw new NoPermissionException("Policy forbids user " + u
132                             + " to access data.");
133                 }
134             }
135         }
136     }
137 
138     /***
139      * This method filters the provided parameters against the requested access
140      * and returns only the objects that can be rightfully accessed.
141      * 
142      * @param u
143      * @param t
144      * @param parameters
145      * @param accessTypes
146      * @return
147      * @throws IllegalArgumentException
148      */
149     public Object[] filterObjects(User u, Task t, Object[] parameters,
150             AccessType[] accessTypes) throws IllegalArgumentException {
151         if (u == null) {
152             throw new IllegalArgumentException("Null is not a valid User.");
153         }
154         if (t == null) {
155             throw new IllegalArgumentException("Null is not a valid Task.");
156         }
157         if ((parameters == null) || (accessTypes == null)
158                 || (parameters.length != accessTypes.length)) {
159             throw new IllegalArgumentException(
160                     "accessTyprs and parameters array are not of the same size or are null.");
161         }
162         Vector result = new Vector();
163         PoliciedObject object = null;
164         for (int i = 0; i < parameters.length; i++) {
165             if (parameters[i] instanceof PoliciedObject) {
166                 object = (PoliciedObject) parameters[i];
167                 if ((checkAccess(object.getObjectType(), accessTypes[i]))
168                         && (checkPurpose(u, t, object.getObjectPolicy(),
169                                 accessTypes[i]))) {
170                     result.add(object);
171                 }
172             }
173         }
174         return result.toArray();
175     }
176 
177     /***
178      * 
179      * @param u
180      * @param t
181      * @param parameters
182      * @param accessTypes
183      * @return
184      * @throws NoPermissionException
185      */
186     public boolean canInvoke(User u, Task t, Object[] parameters,
187             AccessType[] accessTypes) throws NoPermissionException {
188         boolean result = false;
189         try {
190             checkParameters(u, t, parameters, accessTypes);
191             result = true;
192         } catch (NoPermissionException e) {
193             // TODO
194         } catch (IllegalArgumentException e) {
195             // TODO
196         }
197         return result;
198     }
199 
200     /***
201      * Checks if the user's roles are compatible with the invocation Task and
202      * the subject domain.
203      * 
204      * @param u
205      * @param t
206      * @return
207      */
208     public boolean checkRoles(User u, Task t) {
209         boolean result = false;
210         Role[] roles = u.getRoles();
211         for (int i = 0; (!result) && (i < roles.length); i++) {
212             result = ((roles[i].hasTask(t)) && (roles[i].getDomain() == this.domain));
213         }
214         return result;
215     }
216 
217     /***
218      * This method checks whether the invocation task is compatible with the
219      * subject's task.
220      * 
221      * @param t
222      *            is set by the invocation path. It is otherwise impossible to
223      *            determine a Task that will give a single meaningful business
224      *            Purpose.
225      * @return
226      */
227     public boolean checkTask(Task t) {
228         return (t != null) && (t.isSubTask(this.task));
229     }
230 
231     /***
232      * This method is used to determine if the Subject can access a particular
233      * type.
234      * 
235      * @param type
236      * @param access
237      */
238     public boolean checkAccess(ObjectType type, AccessType access) {
239         return (type != null) && (access != null)
240                 && (type.canAccess(this.domain, access));
241     }
242 
243     /***
244      * Checks if the calling task (business) purpose matches the subject task's
245      * purpose. Checks the ObjectPolicy for the given purpose and access. This
246      * method has to be used to check invocation parameters but also to filter
247      * out return values.
248      * 
249      * @param user
250      * @param t
251      * @param policy
252      * @param access
253      * @return
254      */
255     public boolean checkPurpose(User user, Task t, ObjectPolicy policy,
256             AccessType access) {
257         return (user != null) && (t != null) && (policy != null)
258                 && (access != null)
259                 && (t.getPurpose().hasParent(this.task.getPurpose()))
260                 && (policy.accessAuthorized(user, t.getPurpose(), access));
261     }
262 
263 }