Clover icon

sunshower-core

  1. Project Clover database Fri Apr 6 2018 03:27:42 UTC
  2. Package io.sunshower.service.security

File UUIDEnabledLookupStrategy.java

 

Coverage histogram

../../../../img/srcFileCovDistChart0.png
60% of files have more coverage

Code metrics

46
160
30
3
649
394
59
0.37
5.33
10
1.97

Classes

Class Line # Actions
UUIDEnabledLookupStrategy 54 112 38
0.00%
UUIDEnabledLookupStrategy.ProcessResultSet 486 39 12
0.00%
UUIDEnabledLookupStrategy.StubAclParent 604 9 9
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10    * Unless required by applicable law or agreed to in writing, software
11    * distributed under the License is distributed on an "AS IS" BASIS,
12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    * See the License for the specific language governing permissions and
14    * limitations under the License.
15    */
16    package io.sunshower.service.security;
17   
18    import java.io.Serializable;
19    import java.lang.reflect.Field;
20    import java.sql.ResultSet;
21    import java.sql.SQLException;
22    import java.util.*;
23    import javax.sql.DataSource;
24    import org.springframework.jdbc.core.JdbcTemplate;
25    import org.springframework.jdbc.core.ResultSetExtractor;
26    import org.springframework.security.acls.domain.AccessControlEntryImpl;
27    import org.springframework.security.acls.domain.AclAuthorizationStrategy;
28    import org.springframework.security.acls.domain.AclImpl;
29    import org.springframework.security.acls.domain.AuditLogger;
30    import org.springframework.security.acls.domain.DefaultPermissionFactory;
31    import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
32    import org.springframework.security.acls.domain.GrantedAuthoritySid;
33    import org.springframework.security.acls.domain.ObjectIdentityImpl;
34    import org.springframework.security.acls.domain.PermissionFactory;
35    import org.springframework.security.acls.domain.PrincipalSid;
36    import org.springframework.security.acls.jdbc.LookupStrategy;
37    import org.springframework.security.acls.model.AccessControlEntry;
38    import org.springframework.security.acls.model.Acl;
39    import org.springframework.security.acls.model.AclCache;
40    import org.springframework.security.acls.model.MutableAcl;
41    import org.springframework.security.acls.model.NotFoundException;
42    import org.springframework.security.acls.model.ObjectIdentity;
43    import org.springframework.security.acls.model.Permission;
44    import org.springframework.security.acls.model.PermissionGrantingStrategy;
45    import org.springframework.security.acls.model.Sid;
46    import org.springframework.security.acls.model.UnloadedSidException;
47    import org.springframework.security.util.FieldUtils;
48    import org.springframework.util.Assert;
49   
50    /**
51    * Pretty much copied verbatim from Spring's implementation. It's beyond me why they do not support
52    * UUIDs OOTB
53    */
 
54    public class UUIDEnabledLookupStrategy implements LookupStrategy {
55   
56    public static final String DEFAULT_SELECT_CLAUSE =
57    "select acl_object_identity.object_id_identity, "
58    + "acl_entry.ace_order, "
59    + "acl_object_identity.id as acl_id, "
60    + "acl_object_identity.parent_object, "
61    + "acl_object_identity.entries_inheriting, "
62    + "acl_entry.id as ace_id, "
63    + "acl_entry.mask, "
64    + "acl_entry.granting, "
65    + "acl_entry.audit_success, "
66    + "acl_entry.audit_failure, "
67    + "acl_sid.principal as ace_principal, "
68    + "acl_sid.sid as ace_sid, "
69    + "acli_sid.principal as acl_principal, "
70    + "acli_sid.sid as acl_sid, "
71    + "acl_class.class "
72    + "from acl_object_identity "
73    + "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
74    + "left join acl_class on acl_class.id = acl_object_identity.object_id_class "
75    + "left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity "
76    + "left join acl_sid on acl_entry.sid = acl_sid.id "
77    + "where ( ";
78   
79    private static final String DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE = "(acl_object_identity.id = ?)";
80   
81    private static final String DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE =
82    "(acl_object_identity.object_id_identity = ? and acl_class.class = ?)";
83   
84    public static final String DEFAULT_ORDER_BY_CLAUSE =
85    ") order by acl_object_identity.object_id_identity" + " asc, acl_entry.ace_order asc";
86   
87    // ~ Instance fields
88    // ================================================================================================
89   
90    private final AclAuthorizationStrategy aclAuthorizationStrategy;
91    private PermissionFactory permissionFactory = new DefaultPermissionFactory();
92    private final AclCache aclCache;
93    private final PermissionGrantingStrategy grantingStrategy;
94    private final JdbcTemplate jdbcTemplate;
95    private int batchSize = 50;
96   
97    private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
98    private final Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class, "acl");
99   
100    // SQL Customization fields
101    private String selectClause = DEFAULT_SELECT_CLAUSE;
102    private String lookupPrimaryKeysWhereClause = DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE;
103    private String lookupObjectIdentitiesWhereClause = DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE;
104    private String orderByClause = DEFAULT_ORDER_BY_CLAUSE;
105   
106    // ~ Constructors
107    // ===================================================================================================
108   
109    /**
110    * Constructor accepting mandatory arguments
111    *
112    * @param dataSource to access the database
113    * @param aclCache the cache where fully-loaded elements can be stored
114    * @param aclAuthorizationStrategy authorization strategy (required)
115    */
 
116  0 toggle public UUIDEnabledLookupStrategy(
117    DataSource dataSource,
118    AclCache aclCache,
119    AclAuthorizationStrategy aclAuthorizationStrategy,
120    AuditLogger auditLogger) {
121  0 this(
122    dataSource,
123    aclCache,
124    aclAuthorizationStrategy,
125    new DefaultPermissionGrantingStrategy(auditLogger));
126    }
127   
128    /**
129    * Creates a new instance
130    *
131    * @param dataSource to access the database
132    * @param aclCache the cache where fully-loaded elements can be stored
133    * @param aclAuthorizationStrategy authorization strategy (required)
134    * @param grantingStrategy the PermissionGrantingStrategy
135    */
 
136  0 toggle public UUIDEnabledLookupStrategy(
137    DataSource dataSource,
138    AclCache aclCache,
139    AclAuthorizationStrategy aclAuthorizationStrategy,
140    PermissionGrantingStrategy grantingStrategy) {
141  0 Assert.notNull(dataSource, "DataSource required");
142  0 Assert.notNull(aclCache, "AclCache required");
143  0 Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
144  0 Assert.notNull(grantingStrategy, "grantingStrategy required");
145  0 jdbcTemplate = new JdbcTemplate(dataSource);
146  0 this.aclCache = aclCache;
147  0 this.aclAuthorizationStrategy = aclAuthorizationStrategy;
148  0 this.grantingStrategy = grantingStrategy;
149  0 fieldAces.setAccessible(true);
150  0 fieldAcl.setAccessible(true);
151    }
152   
153    // ~ Methods
154    // ========================================================================================================
155   
 
156  0 toggle private String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
157  0 assert requiredRepetitions > 0 : "requiredRepetitions must be > 0";
158   
159  0 final String startSql = selectClause;
160   
161  0 final String endSql = orderByClause;
162   
163  0 StringBuilder sqlStringBldr =
164    new StringBuilder(
165    startSql.length()
166    + endSql.length()
167    + requiredRepetitions * (repeatingSql.length() + 4));
168  0 sqlStringBldr.append(startSql);
169   
170  0 for (int i = 1; i <= requiredRepetitions; i++) {
171  0 sqlStringBldr.append(repeatingSql);
172   
173  0 if (i != requiredRepetitions) {
174  0 sqlStringBldr.append(" or ");
175    }
176    }
177   
178  0 sqlStringBldr.append(endSql);
179   
180  0 return sqlStringBldr.toString();
181    }
182   
 
183  0 toggle @SuppressWarnings("unchecked")
184    private List<AccessControlEntryImpl> readAces(AclImpl acl) {
185  0 try {
186  0 return (List<AccessControlEntryImpl>) fieldAces.get(acl);
187    } catch (IllegalAccessException e) {
188  0 throw new IllegalStateException("Could not obtain AclImpl.aces field", e);
189    }
190    }
191   
 
192  0 toggle private void setAclOnAce(AccessControlEntryImpl ace, AclImpl acl) {
193  0 try {
194  0 fieldAcl.set(ace, acl);
195    } catch (IllegalAccessException e) {
196  0 throw new IllegalStateException(
197    "Could not or set AclImpl on AccessControlEntryImpl fields", e);
198    }
199    }
200   
 
201  0 toggle private void setAces(AclImpl acl, List<AccessControlEntryImpl> aces) {
202  0 try {
203  0 fieldAces.set(acl, aces);
204    } catch (IllegalAccessException e) {
205  0 throw new IllegalStateException("Could not set AclImpl entries", e);
206    }
207    }
208   
 
209  0 toggle private void lookupPrimaryKeys(
210    final Map<Serializable, Acl> acls, final Set<UUID> findNow, final List<Sid> sids) {
211  0 Assert.notNull(acls, "ACLs are required");
212  0 Assert.notEmpty(findNow, "Items to find now required");
213   
214  0 String sql = computeRepeatingSql(lookupPrimaryKeysWhereClause, findNow.size());
215   
216  0 Set<UUID> parentsToLookup =
217    jdbcTemplate.query(
218    sql,
219    ps -> {
220  0 int i = 0;
221   
222  0 for (UUID toFind : findNow) {
223  0 i++;
224  0 ps.setObject(i, toFind);
225    }
226    },
227    new ProcessResultSet(acls, sids));
228   
229    // Lookup the parents, now that our JdbcTemplate has released the database
230    // connection (SEC-547)
231  0 if (parentsToLookup.size() > 0) {
232  0 lookupPrimaryKeys(acls, parentsToLookup, sids);
233    }
234    }
235   
 
236  0 toggle public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
237  0 Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
238  0 Assert.notEmpty(objects, "Objects to lookup required");
239   
240    // Map<ObjectIdentity,Acl>
241  0 Map<ObjectIdentity, Acl> result = new HashMap<ObjectIdentity, Acl>(); // contains
242    // FULLY
243    // loaded
244    // Acl
245    // objects
246   
247  0 Set<ObjectIdentity> currentBatchToLoad = new HashSet<ObjectIdentity>();
248   
249  0 for (int i = 0; i < objects.size(); i++) {
250  0 final ObjectIdentity oid = objects.get(i);
251  0 boolean aclFound = false;
252   
253    // Check we don't already have this ACL in the results
254  0 if (result.containsKey(oid)) {
255  0 aclFound = true;
256    }
257   
258    // Check cache for the present ACL entry
259  0 if (!aclFound) {
260  0 Acl acl = aclCache.getFromCache(oid);
261   
262    // Ensure any cached element supports all the requested SIDs
263    // (they should always, as our base impl doesn't filter on SID)
264  0 if (acl != null) {
265  0 if (acl.isSidLoaded(sids)) {
266  0 result.put(acl.getObjectIdentity(), acl);
267  0 aclFound = true;
268    } else {
269  0 throw new IllegalStateException(
270    "Error: SID-filtered element detected when implementation does not perform SID filtering "
271    + "- have you added something to the cache manually?");
272    }
273    }
274    }
275   
276    // Load the ACL from the database
277  0 if (!aclFound) {
278  0 currentBatchToLoad.add(oid);
279    }
280   
281    // Is it time to load from JDBC the currentBatchToLoad?
282  0 if ((currentBatchToLoad.size() == this.batchSize) || ((i + 1) == objects.size())) {
283  0 if (currentBatchToLoad.size() > 0) {
284  0 Map<ObjectIdentity, Acl> loadedBatch = lookupObjectIdentities(currentBatchToLoad, sids);
285   
286    // Add loaded batch (all elements 100% initialized) to results
287  0 result.putAll(loadedBatch);
288   
289    // Add the loaded batch to the cache
290   
291  0 for (Acl loadedAcl : loadedBatch.values()) {
292  0 aclCache.putInCache((AclImpl) loadedAcl);
293    }
294   
295  0 currentBatchToLoad.clear();
296    }
297    }
298    }
299   
300  0 return result;
301    }
302   
303    /**
304    * Looks up a batch of <code>ObjectIdentity</code>s directly from the database.
305    *
306    * <p>The caller is responsible for optimization issues, such as selecting the identities to
307    * lookup, ensuring the cache doesn't contain them already, and adding the returned elements to
308    * the cache etc.
309    *
310    * <p>This subclass is required to return fully valid <code>Acl</code>s, including
311    * properly-configured parent ACLs.
312    */
 
313  0 toggle private Map<ObjectIdentity, Acl> lookupObjectIdentities(
314    final Collection<ObjectIdentity> objectIdentities, List<Sid> sids) {
315  0 Assert.notEmpty(objectIdentities, "Must provide identities to lookup");
316   
317  0 final Map<Serializable, Acl> acls = new HashMap<Serializable, Acl>(); // contains
318    // Acls
319    // with
320    // StubAclParents
321   
322    // Make the "acls" map contain all requested objectIdentities
323    // (including markers to each parent in the hierarchy)
324  0 String sql = computeRepeatingSql(lookupObjectIdentitiesWhereClause, objectIdentities.size());
325   
326  0 Set<UUID> parentsToLookup =
327    jdbcTemplate.query(
328    sql,
329    ps -> {
330  0 int i = 0;
331  0 for (ObjectIdentity oid : objectIdentities) {
332    // Determine prepared statement values for this iteration
333  0 String type = oid.getType();
334   
335    // No need to check for nulls, as guaranteed non-null by
336    // ObjectIdentity.getIdentifier() interface contract
337  0 UUID identifier = (UUID) oid.getIdentifier();
338   
339  0 ps.setObject((2 * i) + 1, identifier);
340    // Inject values
341    // ps.setLong((2 * i) + 1, id);
342  0 ps.setString((2 * i) + 2, type);
343  0 i++;
344    }
345    },
346    new ProcessResultSet(acls, sids));
347   
348    // Lookup the parents, now that our JdbcTemplate has released the database
349    // connection (SEC-547)
350  0 if (parentsToLookup.size() > 0) {
351  0 lookupPrimaryKeys(acls, parentsToLookup, sids);
352    }
353   
354    // Finally, convert our "acls" containing StubAclParents into true Acls
355  0 Map<ObjectIdentity, Acl> resultMap = new HashMap<>();
356   
357  0 for (Acl inputAcl : acls.values()) {
358  0 Assert.isInstanceOf(AclImpl.class, inputAcl, "Map should have contained an AclImpl");
359   
360  0 Acl result = convert(acls, (UUID) ((AclImpl) inputAcl).getId());
361  0 resultMap.put(result.getObjectIdentity(), result);
362    }
363   
364  0 return resultMap;
365    }
366   
367    /**
368    * The final phase of converting the <code>Map</code> of <code>AclImpl</code> instances which
369    * contain <code>StubAclParent</code>s into proper, valid <code>AclImpl</code>s with correct ACL
370    * parents.
371    *
372    * @param inputMap the unconverted <code>AclImpl</code>s
373    * @param currentIdentity the current<code>Acl</code> that we wish to convert (this may be
374    */
 
375  0 toggle private AclImpl convert(Map<Serializable, Acl> inputMap, UUID currentIdentity) {
376  0 Assert.notEmpty(inputMap, "InputMap required");
377  0 Assert.notNull(currentIdentity, "CurrentIdentity required");
378   
379    // Retrieve this Acl from the InputMap
380  0 Acl uncastAcl = inputMap.get(currentIdentity);
381  0 Assert.isInstanceOf(AclImpl.class, uncastAcl, "The inputMap contained a non-AclImpl");
382   
383  0 AclImpl inputAcl = (AclImpl) uncastAcl;
384   
385  0 Acl parent = inputAcl.getParentAcl();
386   
387  0 if ((parent != null) && parent instanceof StubAclParent) {
388    // Lookup the parent
389  0 StubAclParent stubAclParent = (StubAclParent) parent;
390  0 parent = convert(inputMap, stubAclParent.getId());
391    }
392   
393    // Now we have the parent (if there is one), create the true AclImpl
394  0 AclImpl result =
395    new AclImpl(
396    inputAcl.getObjectIdentity(),
397    inputAcl.getId(),
398    aclAuthorizationStrategy,
399    grantingStrategy,
400    parent,
401    null,
402    inputAcl.isEntriesInheriting(),
403    inputAcl.getOwner());
404   
405    // Copy the "aces" from the input to the destination
406   
407    // Obtain the "aces" from the input ACL
408  0 List<AccessControlEntryImpl> aces = readAces(inputAcl);
409   
410    // Create a list in which to store the "aces" for the "result" AclImpl instance
411  0 List<AccessControlEntryImpl> acesNew = new ArrayList<AccessControlEntryImpl>();
412   
413    // Iterate over the "aces" input and replace each nested
414    // AccessControlEntryImpl.getAcl() with the new "result" AclImpl instance
415    // This ensures StubAclParent instances are removed, as per SEC-951
416  0 for (AccessControlEntryImpl ace : aces) {
417  0 setAclOnAce(ace, result);
418  0 acesNew.add(ace);
419    }
420   
421    // Finally, now that the "aces" have been converted to have the "result" AclImpl
422    // instance, modify the "result" AclImpl instance
423  0 setAces(result, acesNew);
424   
425  0 return result;
426    }
427   
428    /**
429    * Creates a particular implementation of {@link Sid} depending on the arguments.
430    *
431    * @param sid the name of the sid representing its unique identifier. In typical ACL database
432    * schema it's located in table {@code acl_sid} table, {@code sid} column.
433    * @param isPrincipal whether it's a user or granted authority like role
434    * @return the instance of Sid with the {@code sidName} as an identifier
435    */
 
436  0 toggle protected Sid createSid(boolean isPrincipal, String sid) {
437  0 if (isPrincipal) {
438  0 return new PrincipalSid(sid);
439    } else {
440  0 return new GrantedAuthoritySid(sid);
441    }
442    }
443   
444    /**
445    * Sets the {@code PermissionFactory} instance which will be used to convert loaded permission
446    * data values to {@code Permission}s. A {@code DefaultPermissionFactory} will be used by default.
447    *
448    * @param permissionFactory
449    */
 
450  0 toggle public final void setPermissionFactory(PermissionFactory permissionFactory) {
451  0 this.permissionFactory = permissionFactory;
452    }
453   
 
454  0 toggle public final void setBatchSize(int batchSize) {
455  0 this.batchSize = batchSize;
456    }
457   
458    /**
459    * The SQL for the select clause. If customizing in order to modify column names, schema etc, the
460    * other SQL customization fields must also be set to match.
461    *
462    * @param selectClause the select clause, which defaults to {@link #DEFAULT_SELECT_CLAUSE}.
463    */
 
464  0 toggle public final void setSelectClause(String selectClause) {
465  0 this.selectClause = selectClause;
466    }
467   
468    /** The SQL for the where clause used in the <tt>lookupPrimaryKey</tt> method. */
 
469  0 toggle public final void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
470  0 this.lookupPrimaryKeysWhereClause = lookupPrimaryKeysWhereClause;
471    }
472   
473    /** The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method. */
 
474  0 toggle public final void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
475  0 this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
476    }
477   
478    /** The SQL for the "order by" clause used in both queries. */
 
479  0 toggle public final void setOrderByClause(String orderByClause) {
480  0 this.orderByClause = orderByClause;
481    }
482   
483    // ~ Inner Classes
484    // ==================================================================================================
485   
 
486    private class ProcessResultSet implements ResultSetExtractor<Set<UUID>> {
487    private final Map<Serializable, Acl> acls;
488    private final List<Sid> sids;
489   
 
490  0 toggle public ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
491  0 Assert.notNull(acls, "ACLs cannot be null");
492  0 this.acls = acls;
493  0 this.sids = sids; // can be null
494    }
495   
 
496  0 toggle public Set<UUID> extractData(ResultSet rs) throws SQLException {
497  0 Set<UUID> parentIdsToLookup = new HashSet<>(); // Set of parent_id Longs
498   
499  0 while (rs.next()) {
500    // Convert current row into an Acl (albeit with a StubAclParent)
501  0 convertCurrentResultIntoObject(acls, rs);
502   
503    // Figure out if this row means we need to lookup another parent
504  0 UUID parentId = (UUID) rs.getObject("parent_object");
505   
506  0 if (parentId != null) {
507    // See if it's already in the "acls"
508   
509  0 if (acls.containsKey(parentId)) {
510  0 continue; // skip this while iteration
511    }
512   
513    // Now try to find it in the cache
514  0 MutableAcl cached = aclCache.getFromCache(parentId);
515   
516  0 if ((cached == null) || !cached.isSidLoaded(sids)) {
517  0 parentIdsToLookup.add(parentId);
518    } else {
519    // Pop into the acls map, so our convert method doesn't
520    // need to deal with an unsynchronized AclCache
521  0 acls.put(cached.getId(), cached);
522    }
523    }
524    }
525   
526    // Return the parents left to lookup to the caller
527  0 return parentIdsToLookup;
528    }
529   
530    /**
531    * Accepts the current <code>ResultSet</code> row, and converts it into an <code>AclImpl</code>
532    * that contains a <code>StubAclParent</code>
533    *
534    * @param acls the Map we should add the converted Acl to
535    * @param rs the ResultSet focused on a current row
536    * @throws SQLException if something goes wrong converting values
537    */
 
538  0 toggle private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls, ResultSet rs)
539    throws SQLException {
540  0 UUID id = fromBytes(rs.getObject("acl_id"));
541   
542    // If we already have an ACL for this ID, just create the ACE
543  0 Acl acl = acls.get(id);
544   
545  0 if (acl == null) {
546    // Make an AclImpl and pop it into the Map
547  0 ObjectIdentity objectIdentity =
548    new ObjectIdentityImpl(
549    rs.getString("class"), (UUID) rs.getObject("object_id_identity"));
550   
551  0 Acl parentAcl = null;
552  0 UUID parentAclId = (UUID) rs.getObject("parent_object");
553   
554  0 if (parentAclId != null) {
555  0 parentAcl = new StubAclParent(parentAclId);
556    }
557   
558  0 boolean entriesInheriting = rs.getBoolean("entries_inheriting");
559  0 Sid owner = createSid(rs.getBoolean("acl_principal"), rs.getString("acl_sid"));
560   
561  0 acl =
562    new AclImpl(
563    objectIdentity,
564    id,
565    aclAuthorizationStrategy,
566    grantingStrategy,
567    parentAcl,
568    null,
569    entriesInheriting,
570    owner);
571   
572  0 acls.put(id, acl);
573    }
574   
575    // Add an extra ACE to the ACL (ORDER BY maintains the ACE list order)
576    // It is permissible to have no ACEs in an ACL (which is detected by a null
577    // ACE_SID)
578  0 if (rs.getString("ace_sid") != null) {
579    // Long aceId = new Long(rs.getLong("ace_id"));
580  0 UUID aceId = (UUID) rs.getObject("ace_id");
581  0 Sid recipient = createSid(rs.getBoolean("ace_principal"), rs.getString("ace_sid"));
582   
583  0 int mask = rs.getInt("mask");
584  0 Permission permission = permissionFactory.buildFromMask(mask);
585  0 boolean granting = rs.getBoolean("granting");
586  0 boolean auditSuccess = rs.getBoolean("audit_success");
587  0 boolean auditFailure = rs.getBoolean("audit_failure");
588   
589  0 AccessControlEntryImpl ace =
590    new AccessControlEntryImpl(
591    aceId, acl, recipient, permission, granting, auditSuccess, auditFailure);
592   
593    // Field acesField = FieldUtils.getField(AclImpl.class, "aces");
594  0 List<AccessControlEntryImpl> aces = readAces((AclImpl) acl);
595   
596    // Add the ACE if it doesn't already exist in the ACL.aces field
597  0 if (!aces.contains(ace)) {
598  0 aces.add(ace);
599    }
600    }
601    }
602    }
603   
 
604    private static class StubAclParent implements Acl {
605    private final UUID id;
606   
 
607  0 toggle public StubAclParent(UUID id) {
608  0 this.id = id;
609    }
610   
 
611  0 toggle public List<AccessControlEntry> getEntries() {
612  0 throw new UnsupportedOperationException("Stub only");
613    }
614   
 
615  0 toggle public UUID getId() {
616  0 return id;
617    }
618   
 
619  0 toggle public ObjectIdentity getObjectIdentity() {
620  0 throw new UnsupportedOperationException("Stub only");
621    }
622   
 
623  0 toggle public Sid getOwner() {
624  0 throw new UnsupportedOperationException("Stub only");
625    }
626   
 
627  0 toggle public Acl getParentAcl() {
628  0 throw new UnsupportedOperationException("Stub only");
629    }
630   
 
631  0 toggle public boolean isEntriesInheriting() {
632  0 throw new UnsupportedOperationException("Stub only");
633    }
634   
 
635  0 toggle public boolean isGranted(
636    List<Permission> permission, List<Sid> sids, boolean administrativeMode)
637    throws NotFoundException, UnloadedSidException {
638  0 throw new UnsupportedOperationException("Stub only");
639    }
640   
 
641  0 toggle public boolean isSidLoaded(List<Sid> sids) {
642  0 throw new UnsupportedOperationException("Stub only");
643    }
644    }
645   
 
646  0 toggle static UUID fromBytes(Object bytes) {
647  0 return (UUID) bytes;
648    }
649    }