KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > GranteeManager


1 /* Copyright (c) 2001-2005, The HSQL Development Group
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the HSQL Development Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31
32 package org.hsqldb;
33
34 import org.hsqldb.lib.HashMappedList;
35 import org.hsqldb.lib.HashSet;
36 import org.hsqldb.lib.HsqlArrayList;
37 import org.hsqldb.lib.IntKeyHashMap;
38 import org.hsqldb.lib.IntValueHashMap;
39 import org.hsqldb.lib.Iterator;
40 import org.hsqldb.lib.StringUtil;
41 import org.hsqldb.lib.Collection;
42 import org.hsqldb.lib.Set;
43
44 /**
45  * Contains a set of Grantee objects, and supports operations for creating,
46  * finding, modifying and deleting Grantee objects for a Database; plus
47  * Administrative privileges.
48  *
49  * @author boucherb@users
50  * @author fredt@users
51  * @author unsaved@users
52  *
53  * @version 1.8.0
54  * @since 1.8.0
55  * @see Grantee
56  */

57 class GranteeManager implements GrantConstants {
58
59     /**
60      * The role name reserved for authorization of INFORMATION_SCHEMA and
61      * system objects.
62      */

63     static final String JavaDoc SYSTEM_AUTHORIZATION_NAME = "_SYSTEM";
64
65     /** The role name reserved for ADMIN users. */
66     static final String JavaDoc DBA_ADMIN_ROLE_NAME = "DBA";
67
68     /** The role name reserved for the special PUBLIC pseudo-user. */
69     static final String JavaDoc PUBLIC_ROLE_NAME = "PUBLIC";
70
71     /**
72      * An empty list that is returned from
73      * {@link #listTablePrivileges listTablePrivileges} when
74      * it is detected that neither this <code>User</code> object or
75      * its <code>PUBLIC</code> <code>User</code> object attribute have been
76      * granted any rights on the <code>Table</code> object identified by
77      * the specified <code>HsqlName</code> object.
78      *
79      */

80     static final String JavaDoc[] emptyRightsList = new String JavaDoc[0];
81
82     /**
83      * MAP: int => HsqlArrayList. <p>
84      *
85      * This map caches the lists of <code>String</code> objects naming the rights
86      * corresponding to each valid set of rights flags, as returned by
87      * {@link #listRightNames listRightNames}
88      *
89      */

90     static final IntKeyHashMap hRightsLists = new IntKeyHashMap();
91
92     /**
93      * Used to provide access to the RoleManager for Grantee.isAccessible()
94      * lookups
95      */

96     /*
97      * Our map here has the same keys as the UserManager map
98      * EXCEPT that we include all roles, including the SYSTEM_AUTHORIZATION_NAME
99      * because we need o keep track of those permissions, but not his identity.
100      * I.e., our list here is all-inclusive, whether the User or Role is
101      * visible to database users or not.
102      */

103
104     /**
105      * Map of String-to-Grantee-objects.<p>
106      * Primary object maintained by this class
107      */

108     private HashMappedList map = new HashMappedList();
109
110     /**
111      * This object's set of Role objects. <p>
112      * role-Strings-to-Grantee-object
113      */

114     private HashMappedList roleMap = new HashMappedList();
115
116     /**
117      * Construct the GranteeManager for a Database.
118      *
119      * Construct special Grantee objects for PUBLIC and SYS, and add them
120      * to the Grantee map.
121      * We depend on the corresponding User accounts being created
122      * independently so as to remove a dependency to the UserManager class.
123      *
124      * @param inDatabase Only needed to link to the RoleManager later on.
125      */

126     public GranteeManager(Database inDatabase) throws HsqlException {
127         addRole(GranteeManager.DBA_ADMIN_ROLE_NAME);
128         getRole(GranteeManager.DBA_ADMIN_ROLE_NAME).setAdminDirect();
129     }
130
131     static final IntValueHashMap rightsStringLookup = new IntValueHashMap(7);
132
133     static {
134         rightsStringLookup.put(S_R_ALL, ALL);
135         rightsStringLookup.put(S_R_SELECT, SELECT);
136         rightsStringLookup.put(S_R_UPDATE, UPDATE);
137         rightsStringLookup.put(S_R_DELETE, DELETE);
138         rightsStringLookup.put(S_R_INSERT, INSERT);
139     }
140
141     /**
142      * Grants the rights represented by the rights argument on
143      * the database object identified by the dbobject argument
144      * to the Grantee object identified by name argument.<p>
145      *
146      * Note: For the dbobject argument, Java Class objects are identified
147      * using a String object whose value is the fully qualified name
148      * of the Class, while Table and other objects are
149      * identified by an HsqlName object. A Table
150      * object identifier must be precisely the one obtained by calling
151      * table.getName(); if a different HsqlName
152      * object with an identical name attribute is specified, then
153      * rights checks and tests will fail, since the HsqlName
154      * class implements its {@link HsqlName#hashCode hashCode} and
155      * {@link HsqlName#equals equals} methods based on pure object
156      * identity, rather than on attribute values. <p>
157      */

158     void grant(String JavaDoc name, Object JavaDoc dbobject,
159                int rights) throws HsqlException {
160
161         Grantee g = get(name);
162
163         if (g == null) {
164             throw Trace.error(Trace.NO_SUCH_GRANTEE, name);
165         }
166
167         if (isImmutable(name)) {
168             throw Trace.error(Trace.NONMOD_GRANTEE, name);
169         }
170
171         g.grant(dbobject, rights);
172         g.updateAllRights();
173
174         if (g.isRole) {
175             updateAllRights(g);
176         }
177     }
178
179     /**
180      * Grant a role to this Grantee.
181      */

182     void grant(String JavaDoc name, String JavaDoc role) throws HsqlException {
183
184         Grantee grantee = get(name);
185
186         if (grantee == null) {
187             throw Trace.error(Trace.NO_SUCH_GRANTEE, name);
188         }
189
190         if (isImmutable(name)) {
191             throw Trace.error(Trace.NONMOD_GRANTEE, name);
192         }
193
194         Grantee r = get(role);
195
196         if (r == null) {
197             throw Trace.error(Trace.NO_SUCH_ROLE, role);
198         }
199
200         if (role.equals(name)) {
201             throw Trace.error(Trace.CIRCULAR_GRANT, name);
202         }
203
204         // boucherb@users 20050515
205
// SQL 2003 Foundation, 4.34.3
206
// No cycles of role grants are allowed.
207
if (r.hasRole(name)) {
208
209             // boucherb@users
210
// TODO: Correct reporting of actual grant path
211
throw Trace.error(Trace.CIRCULAR_GRANT,
212                               Trace.getMessage(Trace.ALREADY_HAVE_ROLE)
213                               + " GRANT " + name + " TO " + role);
214         }
215
216         if (grantee.getDirectRoles().contains(role)) {
217             throw Trace.error(Trace.ALREADY_HAVE_ROLE, role);
218         }
219
220         grantee.grant(role);
221         grantee.updateAllRights();
222
223         if (grantee.isRole) {
224             updateAllRights(grantee);
225         }
226     }
227
228     /**
229      * Revoke a role from a Grantee
230      */

231     void revoke(String JavaDoc name, String JavaDoc role) throws HsqlException {
232
233         Grantee g = get(name);
234
235         if (g == null) {
236             throw Trace.error(Trace.NO_SUCH_GRANTEE, name);
237         }
238
239         g.revoke(role);
240         g.updateAllRights();
241
242         if (g.isRole) {
243             updateAllRights(g);
244         }
245     }
246
247     /**
248      * Revokes the rights represented by the rights argument on
249      * the database object identified by the dbobject argument
250      * from the User object identified by the name
251      * argument.<p>
252      * @see #grant
253      */

254     void revoke(String JavaDoc name, Object JavaDoc dbobject,
255                 int rights) throws HsqlException {
256
257         Grantee g = get(name);
258
259         g.revoke(dbobject, rights);
260         g.updateAllRights();
261
262         if (g.isRole) {
263             updateAllRights(g);
264         }
265     }
266
267     /**
268      * Removes a role without any privileges from all grantees
269      */

270     void removeEmptyRole(Grantee role) {
271
272         String JavaDoc name = role.getName();
273
274         for (int i = 0; i < map.size(); i++) {
275             Grantee grantee = (Grantee) map.get(i);
276
277             grantee.roles.remove(name);
278         }
279     }
280
281     /**
282      * Removes all rights mappings for the database object identified by
283      * the dbobject argument from all Grantee objects in the set.
284      */

285     void removeDbObject(Object JavaDoc dbobject) {
286
287         for (int i = 0; i < map.size(); i++) {
288             Grantee g = (Grantee) map.get(i);
289
290             g.revokeDbObject(dbobject);
291         }
292     }
293
294     /**
295      * First updates all ROLE Grantee objects. Then updates all USER Grantee
296      * Objects.
297      */

298     void updateAllRights(Grantee role) {
299
300         String JavaDoc name = role.getName();
301
302         for (int i = 0; i < map.size(); i++) {
303             Grantee grantee = (Grantee) map.get(i);
304
305             if (grantee.isRole) {
306                 grantee.updateNestedRoles(name);
307             }
308         }
309
310         for (int i = 0; i < map.size(); i++) {
311             Grantee grantee = (Grantee) map.get(i);
312
313             if (!grantee.isRole) {
314                 grantee.updateAllRights();
315             }
316         }
317     }
318
319     /**
320      */

321     public boolean removeGrantee(String JavaDoc name) {
322
323         /*
324          * Explicitly can't remove PUBLIC_USER_NAME and system grantees.
325          */

326         if (isReserved(name)) {
327             return false;
328         }
329
330         Grantee g = (Grantee) map.remove(name);
331
332         if (g == null) {
333             return false;
334         }
335
336         g.clearPrivileges();
337         updateAllRights(g);
338
339         if (g.isRole) {
340             roleMap.remove(name);
341             removeEmptyRole(g);
342         }
343
344         return true;
345     }
346
347     /**
348      * We don't have to worry about anything manually creating a reserved
349      * account, because the reserved accounts are created upon DB
350      * initialization. If somebody tries to create one of these accounts
351      * after that, it will fail because the account will already exist.
352      * (We do prevent them from being removed, elsewhere!)
353      */

354     public Grantee addGrantee(String JavaDoc name) throws HsqlException {
355
356         if (map.containsKey(name)) {
357             throw Trace.error(Trace.GRANTEE_ALREADY_EXISTS, name);
358         }
359
360         Grantee pubGrantee = null;
361
362         if (!isReserved(name)) {
363             pubGrantee = get(PUBLIC_ROLE_NAME);
364
365             if (pubGrantee == null) {
366                 Trace.doAssert(
367                     false, Trace.getMessage(Trace.MISSING_PUBLIC_GRANTEE));
368             }
369         }
370
371         Grantee g = new Grantee(name, pubGrantee, this);
372
373         map.put(name, g);
374
375         return g;
376     }
377
378     /**
379      * Returns true if named Grantee object exists.
380      * This will return true for reserved Grantees
381      * SYSTEM_AUTHORIZATION_NAME, ADMIN_ROLE_NAME, PUBLIC_USER_NAME.
382      */

383     boolean isGrantee(String JavaDoc name) {
384         return (map.containsKey(name));
385     }
386
387     static int getCheckRight(String JavaDoc right) throws HsqlException {
388
389         int r = getRight(right);
390
391         if (r != 0) {
392             return r;
393         }
394
395         throw Trace.error(Trace.NO_SUCH_RIGHT, right);
396     }
397
398     /**
399      * Translate a string representation or right(s) into its numeric form.
400      */

401     static int getRight(String JavaDoc right) {
402         return rightsStringLookup.get(right, 0);
403     }
404
405     /**
406      * Returns a comma separated list of right names corresponding to the
407      * right flags set in the right argument. <p>
408      */

409     static String JavaDoc getRightsList(int rights) {
410
411 // checkValidFlags(right);
412
if (rights == 0) {
413             return null;
414         }
415
416         if (rights == ALL) {
417             return S_R_ALL;
418         }
419
420         return StringUtil.getList(getRightsArray(rights), ",", "");
421     }
422
423     /**
424      * Retrieves the list of right names represented by the right flags
425      * set in the specified <code>Integer</code> object's <code>int</code>
426      * value. <p>
427      *
428      * @param rights An Integer representing a set of right flags
429      * @return an empty list if the specified <code>Integer</code> object is
430      * null, else a list of rights, as <code>String</code> objects,
431      * represented by the rights flag bits set in the specified
432      * <code>Integer</code> object's int value.
433      *
434      */

435     static String JavaDoc[] getRightsArray(int rights) {
436
437         if (rights == 0) {
438             return emptyRightsList;
439         }
440
441         String JavaDoc[] list = (String JavaDoc[]) hRightsLists.get(rights);
442
443         if (list != null) {
444             return list;
445         }
446
447         list = getRightsArraySub(rights);
448
449         hRightsLists.put(rights, list);
450
451         return list;
452     }
453
454     private static String JavaDoc[] getRightsArraySub(int right) {
455
456 // checkValidFlags(right);
457
if (right == 0) {
458             return emptyRightsList;
459         }
460
461         HsqlArrayList a = new HsqlArrayList();
462         Iterator it = rightsStringLookup.keySet().iterator();
463
464         for (; it.hasNext(); ) {
465             String JavaDoc rightString = (String JavaDoc) it.next();
466
467             if (rightString.equals(S_R_ALL)) {
468                 continue;
469             }
470
471             int i = rightsStringLookup.get(rightString, 0);
472
473             if ((right & i) != 0) {
474                 a.add(rightString);
475             }
476         }
477
478         return (String JavaDoc[]) a.toArray(new String JavaDoc[a.size()]);
479     }
480
481     /**
482      * Retrieves the set of distinct, fully qualified Java <code>Class</code>
483      * names upon which any grants currently exist to elements in
484      * this collection. <p>
485      * @return the set of distinct, fully qualified Java Class names, as
486      * <code>String</code> objects, upon which grants currently exist
487      * to the elements of this collection
488      *
489      */

490     HashSet getGrantedClassNames() throws HsqlException {
491
492         int size;
493         Grantee grantee;
494         HashSet out;
495         Iterator e;
496
497         size = map.size();
498         out = new HashSet();
499
500         for (int i = 0; i < size; i++) {
501             grantee = (Grantee) map.get(i);
502
503             if (grantee == null) {
504                 continue;
505             }
506
507             e = grantee.getGrantedClassNames(false).iterator();
508
509             while (e.hasNext()) {
510                 out.add(e.next());
511             }
512         }
513
514         return out;
515     }
516
517     public Grantee get(String JavaDoc name) {
518         return (Grantee) map.get(name);
519     }
520
521     public Collection getGrantees() {
522         return map.values();
523     }
524
525     public static boolean validRightString(String JavaDoc rightString) {
526         return getRight(rightString) != 0;
527     }
528
529     public static boolean isImmutable(String JavaDoc name) {
530         return name.equals(SYSTEM_AUTHORIZATION_NAME)
531                || name.equals(DBA_ADMIN_ROLE_NAME);
532     }
533
534     public static boolean isReserved(String JavaDoc name) {
535
536         return name.equals(SYSTEM_AUTHORIZATION_NAME)
537                || name.equals(DBA_ADMIN_ROLE_NAME)
538                || name.equals(PUBLIC_ROLE_NAME);
539     }
540
541     /**
542      * Creates a new Role object under management of this object. <p>
543      *
544      * A set of constraints regarding user creation is imposed: <p>
545      *
546      * <OL>
547      * <LI>Can't create a role with name same as any right.
548      *
549      * <LI>If the specified name is null, then an
550      * ASSERTION_FAILED exception is thrown stating that
551      * the name is null.
552      *
553      * <LI>If this object's collection already contains an element whose
554      * name attribute equals the name argument, then
555      * a GRANTEE_ALREADY_EXISTS or ROLE_ALREADY_EXISTS Trace
556      * is thrown.
557      * (This will catch attempts to create Reserved grantee names).
558      * </OL>
559      */

560     String JavaDoc addRole(String JavaDoc name) throws HsqlException {
561
562         /*
563          * Role names can't be right names because that would cause
564          * conflicts with "GRANT name TO...". This doesn't apply to
565          * User names or Grantee names in general, since you can't
566          * "GRANT username TO...". That's why this check is only here.
567          */

568         if (name == null) {
569             Trace.doAssert(false, Trace.getMessage(Trace.NULL_NAME));
570         }
571
572         Grantee g = null;
573
574         if (GranteeManager.validRightString(name)) {
575             throw Trace.error(Trace.ILLEGAL_ROLE_NAME, name);
576         }
577
578         g = addGrantee(name);
579         g.isRole = true;
580
581         boolean result = roleMap.add(name, g);
582
583         if (!result) {
584             throw Trace.error(Trace.ROLE_ALREADY_EXISTS, name);
585         }
586
587         // I don't think can get this trace since every roleMap element
588
// will have a Grantee element which was already verified
589
// above. Easier to leave this check here than research it.
590
return name;
591     }
592
593     /**
594      * Attempts to drop a Role with the specified name
595      * from this object's set. <p>
596      *
597      * A successful drop action consists of: <p>
598      *
599      * <UL>
600      *
601      * <LI>removing the Grantee object with the specified name
602      * from the set.
603      *
604      * <LI>revoking all rights from the removed object<br>
605      * (this ensures that in case there are still references to the
606      * just dropped Grantee object, those references
607      * cannot be used to erronously access database objects).
608      *
609      * </UL> <p>
610      *
611      */

612     void dropRole(String JavaDoc name) throws HsqlException {
613
614         if (name.equals(GranteeManager.DBA_ADMIN_ROLE_NAME)) {
615             throw Trace.error(Trace.ACCESS_IS_DENIED);
616         }
617
618         if (!isRole(name)) {
619             throw Trace.error(Trace.NO_SUCH_ROLE, name);
620         }
621
622         removeGrantee(name);
623         roleMap.remove(name);
624     }
625
626     public Set getRoleNames() {
627         return roleMap.keySet();
628     }
629
630     /**
631      * Returns Grantee for the named Role
632      */

633     Grantee getRole(String JavaDoc name) throws HsqlException {
634
635         if (!isRole(name)) {
636             Trace.doAssert(false, "No role '" + name + "'");
637         }
638
639         Grantee g = (Grantee) roleMap.get(name);
640
641         if (g == null) {
642             throw Trace.error(Trace.MISSING_GRANTEE, name);
643         }
644
645         return g;
646     }
647
648     boolean isRole(String JavaDoc name) throws HsqlException {
649         return roleMap.containsKey(name);
650     }
651 }
652
Popular Tags