001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    
028    package org.opends.server.authorization.dseecompat;
029    
030    import org.opends.server.types.*;
031    import org.opends.server.api.ClientConnection;
032    import org.opends.server.api.Group;
033    import org.opends.server.core.AddOperationBasis;
034    import org.opends.server.api.ConnectionSecurityProvider;
035    import org.opends.server.core.SearchOperation;
036    import org.opends.server.extensions.TLSConnectionSecurityProvider;
037    import org.opends.server.types.Operation;
038    import java.net.InetAddress;
039    import java.util.LinkedList;
040    import java.util.List;
041    import java.util.HashMap;
042    
043    import static org.opends.server.authorization.dseecompat.Aci.*;
044    import static org.opends.server.authorization.dseecompat.AciHandler.*;
045    import org.opends.server.controls.GetEffectiveRights;
046    import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
047    
048    /**
049     *  The AciContainer class contains all of the needed information to perform
050     *  both target match and evaluate an ACI. Target matching is the process
051     *  of testing if an ACI is applicable to an operation, and evaluation is
052     *  the actual access evaluation of the ACI.
053     */
054    public abstract class AciContainer
055    implements AciTargetMatchContext, AciEvalContext {
056    
057        /*
058         * The allow and deny lists.
059         */
060        private LinkedList<Aci> denyList, allowList;
061    
062        /*
063         * The attribute type in the resource entry currently being evaluated.
064         */
065        private AttributeType attributeType;
066    
067        /*
068         * The attribute type value in the resource entry currently being
069         * evaluated.
070         */
071        private AttributeValue attributeValue;
072    
073        /*
074         * True if this is the first attribute type in the resource entry being
075         * evaluated.
076         */
077        private boolean isFirst = false;
078    
079        /*
080         * True if an entry test rule was seen during target matching of an ACI
081         * entry. A entry test rule is an ACI with targetattrs target keyword.
082         */
083        private boolean isEntryTestRule = false;
084    
085        /*
086         * True if the evaluation of an ACI is from the deny list.
087         */
088        private boolean isDenyEval;
089    
090        /*
091         * True if the evaluation is a result of an LDAP add operation.
092         */
093        private boolean isAddOp=false;
094    
095        /*
096         * The rights to use in the evaluation of the LDAP operation.
097         */
098        private int rights;
099    
100        /*
101         * The entry being evaluated (resource entry).
102         */
103        private Entry resourceEntry;
104    
105        /*
106         * Saves the resource entry. Used in geteffectiverights evaluation to
107         * restore the current resource entry state after a read right was
108         * evaluated.
109         */
110        private final Entry saveResourceEntry;
111    
112        /*
113         * The client connection information.
114         */
115        private final ClientConnection clientConnection;
116    
117        /*
118         * The operation being evaluated.
119         */
120        private final Operation operation;
121    
122        /*
123         * True if a targattrfilters match was found.
124         */
125        private boolean targAttrFiltersMatch=false;
126    
127        /*
128         * The authorization entry currently being evaluated. If proxied
129         * authorization is being used and the handler is doing a proxy access
130         * check, then this entry will switched to the original authorization entry
131         * rather than the proxy ID entry. If the check succeeds, it will be
132         * switched back for non-proxy access checking. If proxied authentication
133         * is not being used then this entry never changes.
134         */
135        private Entry authorizationEntry;
136    
137        /*
138         * Used to save the current authorization entry when the authorization
139         * entry is switched during a proxy access check.
140         */
141        private final Entry saveAuthorizationEntry;
142    
143        /*
144         * This entry is only used if proxied authorization is being used.  It is
145         * the original authorization entry before the proxied authorization change.
146         */
147        private Entry origAuthorizationEntry=null;
148    
149        /*
150         * True if proxied authorization is being used.
151         */
152        private boolean proxiedAuthorization=false;
153    
154        /*
155         * Used by proxied authorization processing. True if the entry has already
156         * been processed by an access proxy check. Some operations might perform
157         * several access checks on the same entry (modify DN), this
158         * flag is used to bypass the proxy check after the initial evaluation.
159         */
160        private boolean seenEntry=false;
161    
162        /*
163         *  True if geteffectiverights evaluation is in progress.
164         */
165        private boolean isGetEffectiveRightsEval=false;
166    
167         /*
168         *  True if the operation has a geteffectiverights control.
169         */
170        private boolean hasGetEffectiveRightsControl=false;
171    
172        /*
173         * The geteffectiverights authzID in DN format.
174         */
175        private DN authzid=null;
176    
177        /*
178         * True if the authZid should be used as the client DN, only used in
179         * geteffectiverights evaluation.
180         */
181        private boolean useAuthzid=false;
182    
183        /*
184         * The list of specific attributes to get rights for, in addition to
185         * any attributes requested in the search.
186         */
187        private List<AttributeType> specificAttrs=null;
188    
189        /*
190         * The entry with all of its attributes available. Used in
191         * geteffectiverights read entry level evaluation.
192         */
193        private Entry fullEntry=null;
194    
195        /*
196         * Table of ACIs that have targattrfilter keywords that matched. Used
197         * in geteffectiverights attributeLevel write evaluation.
198         */
199        private final HashMap<Aci,Aci> targAttrFilterAcis=new HashMap<Aci, Aci>();
200    
201        /*
202         * The name of a ACI that decided an evaluation and contained a
203         * targattrfilter keyword. Used in geteffectiverights attributeLevel
204         * write evaluation.
205         */
206        private String targAttrFiltersAciName=null;
207    
208        /*
209         * Value that is used to store the allow/deny result of a deciding ACI
210         * containing a targattrfilter keyword.  Used in geteffectiverights
211         * attributeLevel write evaluation.
212         */
213        private int targAttrMatch=0;
214    
215        /*
216         * The ACI that decided the last evaluation. Used in geteffectiverights
217         * loginfo processing.
218         */
219        private Aci decidingAci=null;
220    
221        /*
222         * The reason the last evaluation decision was made. Used both
223         * in geteffectiverights loginfo processing and attributeLevel write
224         * evaluation.
225         */
226        private EnumEvalReason evalReason=null;
227    
228        /*
229         * A summary string holding the last evaluation information in textual
230         * format. Used in geteffectiverights loginfo processing.
231         */
232        private String summaryString=null;
233    
234       /*
235        * Flag used to determine if ACI all attributes target matched.
236        */
237        private int evalAllAttributes=0;
238    
239       /*
240        * String used to hold a control OID string.
241        */
242        private String controlOID;
243    
244       /*
245        * String used to hold an extended operation OID string.
246        */
247        private String extOpOID;
248    
249      /**
250         * This constructor is used by all currently supported LDAP operations.
251         *
252         * @param operation The Operation object being evaluated and target
253         * matching.
254         *
255         * @param rights The rights array to use in evaluation and target matching.
256         *
257         * @param entry The current entry being evaluated and target matched.
258         */
259        protected AciContainer(Operation operation, int rights, Entry entry) {
260          this.resourceEntry=entry;
261          this.operation=operation;
262          this.clientConnection=operation.getClientConnection();
263          if(operation instanceof AddOperationBasis)
264              this.isAddOp=true;
265    
266          //If the proxied authorization control was processed, then the operation
267          //will contain an attachment containing the original authorization entry.
268          this.origAuthorizationEntry =
269                          (Entry) operation.getAttachment(ORIG_AUTH_ENTRY);
270          if(origAuthorizationEntry != null)
271             this.proxiedAuthorization=true;
272          this.authorizationEntry=operation.getAuthorizationEntry();
273          //The ACI_READ right at constructor time can only be the result of the
274          //AciHandler.filterEntry method. This method processes the
275          //geteffectiverights control, so it needs to check for it.  There are
276          //two other checks done, because the resource entry passed to that method
277          //is filtered (it may not contain enough attribute information
278          //to evaluate correctly). See the the comments below.
279          if(operation instanceof SearchOperation && (rights == ACI_READ)) {
280            //Checks if a geteffectiverights control was sent and
281            //sets up the structures needed.
282            GetEffectiveRights getEffectiveRightsControl =
283                  (GetEffectiveRights)
284                          operation.getAttachment(OID_GET_EFFECTIVE_RIGHTS);
285            if(getEffectiveRightsControl != null) {
286              hasGetEffectiveRightsControl=true;
287              if(getEffectiveRightsControl.getAuthzDN() == null)
288                this.authzid=getClientDN();
289              else
290                this.authzid=getEffectiveRightsControl.getAuthzDN();
291              this.specificAttrs=getEffectiveRightsControl.getAttributes();
292            }
293            //If an ACI evaluated because of an Targetattr="*", then the
294            //AciHandler.maySend method signaled this via adding this attachment
295            //string.
296            String allUserAttrs=
297                      (String)operation.getAttachment(ALL_USER_ATTRS_MATCHED);
298            if(allUserAttrs != null)
299              evalAllAttributes |= ACI_USER_ATTR_STAR_MATCHED;
300            //If an ACI evaluated because of an Targetattr="+", then the
301            //AciHandler.maySend method signaled this via adding this attachment
302            //string.
303            String allOpAttrs=(String)operation.getAttachment(ALL_OP_ATTRS_MATCHED);
304            if(allOpAttrs != null)
305              evalAllAttributes |= ACI_OP_ATTR_PLUS_MATCHED;
306    
307            //The AciHandler.maySend method also adds the full attribute version of
308            //the resource entry in this attachment.
309            fullEntry=(Entry)operation.getAttachment(ALL_ATTRS_RESOURCE_ENTRY);
310          } else
311            fullEntry=this.resourceEntry;
312          //Reference the current authorization entry, so it can be put back
313          //if an access proxy check was performed.
314          this.saveAuthorizationEntry=this.authorizationEntry;
315          this.saveResourceEntry=this.resourceEntry;
316          this.rights = rights;
317        }
318    
319      /**
320       * Returns true if an entry has already been processed by an access proxy
321       * check.
322       *
323       * @return True if an entry has already been processed by an access proxy
324       * check.
325       */
326       public boolean hasSeenEntry() {
327          return this.seenEntry;
328        }
329    
330      /**
331       * Set to true if an entry has already been processsed by an access proxy
332       * check.
333       *
334       * @param val The value to set the seenEntry boolean to.
335       */
336        public void setSeenEntry(boolean val) {
337         this.seenEntry=val;
338        }
339    
340      /**
341       * {@inheritDoc}
342       */
343        public boolean isProxiedAuthorization() {
344             return this.proxiedAuthorization;
345        }
346    
347      /**
348       * {@inheritDoc}
349       */
350        public boolean isGetEffectiveRightsEval() {
351            return this.isGetEffectiveRightsEval;
352        }
353    
354      /**
355       * The container is going to be used in a geteffectiverights evaluation, set
356       * the flag isGetEffectiveRightsEval to true.
357       */
358      public void setGetEffectiveRightsEval() {
359           this.isGetEffectiveRightsEval=true;
360        }
361    
362      /**
363       * Return true if the container is being used in a geteffectiverights
364       * evaluation.
365       *
366       * @return True if the container is being used in a geteffectiverights
367       * evaluation.
368       */
369        public boolean hasGetEffectiveRightsControl() {
370          return this.hasGetEffectiveRightsControl;
371        }
372    
373      /**
374       * Use the DN from the geteffectiverights control's authzId as the
375       * client DN, rather than the authorization entry's DN.
376       *
377       * @param v The valued to set the useAuthzid to.
378       */
379        public void useAuthzid(boolean v) {
380           this.useAuthzid=v;
381        }
382    
383      /**
384       * Return the list of additional attributes specified in the
385       * geteffectiveritghts control.
386       *
387       * @return The list of attributes to return rights information about in the
388       * entry.
389       */
390        public List<AttributeType> getSpecificAttributes() {
391           return this.specificAttrs;
392        }
393    
394      /**
395       * During the geteffectiverights entrylevel read evaluation, an entry with all
396       * of the attributes used in the AciHandler's maysend method evaluation is
397       * needed to perform the evaluation over again. This entry was saved
398       * in the operation's attachment mechanism when the container was created
399       * during the SearchOperation read evaluation.
400       *
401       * This method is used to replace the current resource entry with that saved
402       * entry to perform the entrylevel read evaluation described above and to
403       * switch back to the current resource entry when needed.
404       *
405       * @param val Specifies if the saved entry should be used or not. True if it
406       * should be used, false if the original resource entry should be used.
407       *
408       */
409        public void useFullResourceEntry(boolean val) {
410          if(val)
411            resourceEntry=fullEntry;
412          else
413            resourceEntry=saveResourceEntry;
414        }
415    
416       /**
417        * {@inheritDoc}
418        */
419        public void addTargAttrFiltersMatchAci(Aci aci) {
420          this.targAttrFilterAcis.put(aci, aci);
421        }
422    
423       /**
424        * {@inheritDoc}
425        */
426        public boolean hasTargAttrFiltersMatchAci(Aci aci) {
427          return this.targAttrFilterAcis.containsKey(aci);
428        }
429    
430       /**
431        * {@inheritDoc}
432        */
433        public boolean isTargAttrFilterMatchAciEmpty() {
434           return this.targAttrFilterAcis.isEmpty();
435        }
436    
437      /**
438       * Reset the values used by the geteffectiverights evaluation to
439       * original values. The geteffectiverights evaluation uses the same container
440       * repeatedly for different rights evaluations (read, write, proxy,...) and
441       * this method resets variables that are specific to a single evaluation.
442       */
443        public void resetEffectiveRightsParams() {
444          this.targAttrFilterAcis.clear();
445          this.decidingAci=null;
446          this.evalReason=null;
447          this.targAttrFiltersMatch=false;
448          this.summaryString=null;
449          this.targAttrMatch=0;
450        }
451    
452       /**
453        * {@inheritDoc}
454        */
455        public void setTargAttrFiltersAciName(String name) {
456          this.targAttrFiltersAciName=name;
457        }
458    
459       /**
460        * {@inheritDoc}
461        */
462        public String getTargAttrFiltersAciName() {
463          return this.targAttrFiltersAciName;
464        }
465    
466       /**
467        * {@inheritDoc}
468        */
469        public void setTargAttrFiltersMatchOp(int flag) {
470          this.targAttrMatch |= flag;
471        }
472    
473       /**
474        * {@inheritDoc}
475        */
476        public boolean hasTargAttrFiltersMatchOp(int flag) {
477           return (this.targAttrMatch & flag) != 0;
478        }
479    
480       /**
481        * {@inheritDoc}
482        */
483        public void setDecidingAci(Aci aci) {
484          this.decidingAci=aci;
485        }
486    
487       /**
488        * {@inheritDoc}
489        */
490        public String getDecidingAciName() {
491          if(this.decidingAci != null)
492             return this.decidingAci.getName();
493          else return null;
494        }
495    
496       /**
497        * {@inheritDoc}
498        */
499        public void setEvalReason(EnumEvalReason reason) {
500          this.evalReason=reason;
501        }
502    
503       /**
504        * {@inheritDoc}
505        */
506        public EnumEvalReason getEvalReason() {
507          return this.evalReason;
508        }
509    
510       /**
511        * {@inheritDoc}
512        */
513        public void setEvalSummary(String summary) {
514          this.summaryString=summary;
515        }
516    
517       /**
518        * {@inheritDoc}
519        */
520         public String getEvalSummary() {
521          return this.summaryString;
522        }
523    
524      /**
525       * Returns true if the geteffectiverights control's authZid DN is equal to the
526       * authoritzation entry's DN.
527       *
528       * @return True if the authZid is equal to the authorization entry's DN.
529       */
530        public boolean isAuthzidAuthorizationDN() {
531         return this.authzid.equals(this.authorizationEntry.getDN());
532        }
533    
534      /**
535       * If the specified value is true, then the original authorization entry,
536       * which is the  entry before the switch performed by the proxied
537       * authorization control processing should be set to the current
538       * authorization entry. If the specified value is false then the proxied
539       * authorization entry is switched back using the saved copy.
540       * @param val The value used to select the authorization entry to use.
541       */
542        public void useOrigAuthorizationEntry(boolean val) {
543          if(val)
544            authorizationEntry=origAuthorizationEntry;
545          else
546            authorizationEntry=saveAuthorizationEntry;
547        }
548    
549       /**
550        * {@inheritDoc}
551        */
552        public void setDenyList(LinkedList<Aci> denys) {
553            denyList=denys;
554        }
555    
556       /**
557        * {@inheritDoc}
558        */
559        public void setAllowList(LinkedList<Aci> allows) {
560            allowList=allows;
561        }
562    
563       /**
564        * {@inheritDoc}
565        */
566        public AttributeType getCurrentAttributeType() {
567            return attributeType;
568        }
569    
570       /**
571        * {@inheritDoc}
572        */
573        public AttributeValue getCurrentAttributeValue() {
574            return attributeValue;
575        }
576    
577       /**
578        * {@inheritDoc}
579        */
580        public void setCurrentAttributeType(AttributeType type) {
581            attributeType=type;
582        }
583    
584       /**
585        * {@inheritDoc}
586        */
587        public void setCurrentAttributeValue(AttributeValue value) {
588            attributeValue=value;
589        }
590    
591       /**
592        * {@inheritDoc}
593        */
594        public boolean isFirstAttribute() {
595            return isFirst;
596        }
597    
598       /**
599        * {@inheritDoc}
600        */
601        public void setIsFirstAttribute(boolean val) {
602            isFirst=val;
603        }
604    
605       /**
606        * {@inheritDoc}
607        */
608        public boolean hasEntryTestRule() {
609            return isEntryTestRule;
610        }
611    
612       /**
613        * {@inheritDoc}
614        */
615       public void setEntryTestRule(boolean val) {
616            isEntryTestRule=val;
617        }
618    
619       /**
620        * {@inheritDoc}
621        */
622        public Entry getResourceEntry() {
623            return resourceEntry;
624        }
625    
626       /**
627        * {@inheritDoc}
628        */
629        public Entry getClientEntry() {
630          return this.authorizationEntry;
631        }
632    
633       /**
634        * {@inheritDoc}
635        */
636        public LinkedList<Aci> getDenyList() {
637            return denyList;
638         }
639    
640       /**
641        * {@inheritDoc}
642        */
643        public LinkedList<Aci> getAllowList() {
644           return allowList;
645        }
646    
647       /**
648        * {@inheritDoc}
649        */
650        public boolean isDenyEval() {
651            return isDenyEval;
652        }
653    
654       /**
655        * {@inheritDoc}
656        */
657        public boolean isAnonymousUser() {
658            return !clientConnection.getAuthenticationInfo().isAuthenticated();
659        }
660    
661       /**
662        * {@inheritDoc}
663        */
664        public void setDenyEval(boolean val) {
665            isDenyEval = val;
666        }
667    
668       /**
669        * {@inheritDoc}
670        */
671        public DN getClientDN() {
672          if(this.useAuthzid)
673            return this.authzid;
674          else
675           if (this.authorizationEntry == null)
676             return DN.nullDN();
677           else
678             return this.authorizationEntry.getDN();
679        }
680    
681       /**
682        * {@inheritDoc}
683        */
684        public DN getResourceDN() {
685            return resourceEntry.getDN();
686        }
687    
688       /**
689        * {@inheritDoc}
690        */
691        public boolean hasRights(int rights) {
692           return (this.rights & rights) != 0;
693        }
694    
695       /**
696        * {@inheritDoc}
697        */
698        public int getRights() {
699            return this.rights;
700        }
701    
702       /**
703        * {@inheritDoc}
704        */
705        public void setRights(int rights) {
706             this.rights=rights;
707        }
708    
709       /**
710        * {@inheritDoc}
711        */
712        public String getHostName() {
713            return clientConnection.getRemoteAddress().getCanonicalHostName();
714        }
715    
716       /**
717        * {@inheritDoc}
718        */
719        public InetAddress getRemoteAddress() {
720            return clientConnection.getRemoteAddress();
721        }
722    
723       /**
724        * {@inheritDoc}
725        */
726        public boolean isAddOperation() {
727            return isAddOp;
728        }
729    
730       /**
731        * {@inheritDoc}
732        */
733        public void setTargAttrFiltersMatch(boolean v) {
734            this.targAttrFiltersMatch=v;
735        }
736    
737       /**
738        * {@inheritDoc}
739        */
740        public boolean getTargAttrFiltersMatch() {
741            return targAttrFiltersMatch;
742        }
743    
744        /**
745        * {@inheritDoc}
746        */
747        public String getControlOID() {
748          return controlOID;
749        }
750    
751       /**
752        * {@inheritDoc}
753        */
754        public String getExtOpOID() {
755          return extOpOID;
756        }
757    
758        /**
759         * Set the the controlOID value to the specified oid string.
760         *
761         * @param oid  The control oid string.
762         */
763        protected void setControlOID(String oid) {
764          this.controlOID=oid;
765        }
766    
767    
768        /**
769         * Set the extended operation OID value to the specified oid string.
770         *
771         * @param oid  The extended operation oid string.
772         */
773        protected void setExtOpOID(String oid) {
774          this.extOpOID=oid;
775        }
776    
777        /**
778         * {@inheritDoc}
779         */
780        public EnumEvalResult hasAuthenticationMethod(EnumAuthMethod authMethod,
781                                                      String saslMech) {
782          EnumEvalResult matched=EnumEvalResult.FALSE;
783    
784          if(authMethod==EnumAuthMethod.AUTHMETHOD_NONE) {
785            /**
786             * None actually means any, in that we don't care what method was used.
787             * This doesn't seem very intuitive or useful, but that's the way it is.
788             */
789            matched = EnumEvalResult.TRUE;
790          } else {
791            /*
792             * Some kind of authentication is required.
793             */
794            AuthenticationInfo authInfo=clientConnection.getAuthenticationInfo();
795            if(authInfo.isAuthenticated()) {
796              if(authMethod==EnumAuthMethod.AUTHMETHOD_SIMPLE) {
797                if(authInfo.hasAuthenticationType(AuthenticationType.SIMPLE)) {
798                  matched = EnumEvalResult.TRUE;
799                }
800              } else if(authMethod == EnumAuthMethod.AUTHMETHOD_SSL) {
801                /*
802                 * This means authentication using a certificate over TLS.
803                 *
804                 * We check the following:
805                 * - SASL EXTERNAL has been used, and
806                 * - TLS is the security provider, and
807                 * - The client provided a certificate.
808                 */
809                if (authInfo.hasAuthenticationType(AuthenticationType.SASL) &&
810                     authInfo.hasSASLMechanism(saslMech)) {
811                  ConnectionSecurityProvider provider =
812                        clientConnection.getConnectionSecurityProvider();
813                  if (provider instanceof TLSConnectionSecurityProvider) {
814                    TLSConnectionSecurityProvider tlsProvider =
815                          (TLSConnectionSecurityProvider) provider;
816                     if (tlsProvider.getClientCertificateChain() != null) {
817                       matched = EnumEvalResult.TRUE;
818                     }
819                  }
820                }
821              } else {
822                // A particular SASL mechanism.
823                if (authInfo.hasAuthenticationType(AuthenticationType.SASL) &&
824                     authInfo.hasSASLMechanism(saslMech)) {
825                  matched = EnumEvalResult.TRUE;
826                }
827              }
828            }
829          }
830          return matched;
831        }
832    
833      /**
834       * {@inheritDoc}
835       */
836        public boolean isMemberOf(Group group) {
837            boolean ret;
838            try {
839              ret=group.isMember(getClientDN());
840            } catch (DirectoryException ex) {
841                ret=false;
842            }
843            return  ret;
844        }
845    
846      /**
847       * {@inheritDoc}
848       */
849        public String rightToString() {
850          if(hasRights(ACI_SEARCH))
851            return "search";
852          else if(hasRights(ACI_COMPARE))
853            return "compare";
854          else if(hasRights(ACI_READ))
855            return "read";
856          else if(hasRights(ACI_DELETE))
857            return "delete";
858          else if(hasRights(ACI_ADD))
859            return "add";
860          else if(hasRights(ACI_WRITE))
861            return "write";
862          else if(hasRights(ACI_PROXY))
863            return "proxy";
864          else if(hasRights(ACI_IMPORT))
865            return "import";
866          else if(hasRights(ACI_EXPORT))
867            return "export";
868          else if(hasRights(ACI_WRITE) &&
869                  hasRights(ACI_SELF))
870            return "selfwrite";
871          return null;
872      }
873    
874      /**
875       * {@inheritDoc}
876       */
877      public  void setEvalUserAttributes(int v) {
878        if(operation instanceof SearchOperation && (rights == ACI_READ)) {
879          if(v == ACI_FOUND_USER_ATTR_RULE) {
880            evalAllAttributes |= ACI_FOUND_USER_ATTR_RULE;
881            evalAllAttributes &= ~ACI_USER_ATTR_STAR_MATCHED;
882          } else
883            evalAllAttributes |= ACI_USER_ATTR_STAR_MATCHED;
884        }
885      }
886    
887         /**
888       * {@inheritDoc}
889       */
890      public  void setEvalOpAttributes(int v) {
891        if(operation instanceof SearchOperation && (rights == ACI_READ)) {
892          if(v == ACI_FOUND_OP_ATTR_RULE) {
893            evalAllAttributes |= ACI_FOUND_OP_ATTR_RULE;
894            evalAllAttributes &= ~ACI_OP_ATTR_PLUS_MATCHED;
895          } else
896            evalAllAttributes |= ACI_OP_ATTR_PLUS_MATCHED;
897        }
898      }
899    
900      /**
901       * {@inheritDoc}
902       */
903      public boolean hasEvalUserAttributes() {
904        return (evalAllAttributes & ACI_FOUND_USER_ATTR_RULE) ==
905                ACI_FOUND_USER_ATTR_RULE;
906      }
907    
908      /**
909       * {@inheritDoc}
910       */
911      public boolean hasEvalOpAttributes() {
912        return (evalAllAttributes & ACI_FOUND_OP_ATTR_RULE) ==
913                ACI_FOUND_OP_ATTR_RULE;
914      }
915    
916      /**
917       * Return true if the evaluating ACI contained a targetattr all
918       * user attributes rule match.
919       *
920       * @return  True if the above condition was seen.
921       **/
922      public boolean hasAllUserAttributes() {
923        return (evalAllAttributes & ACI_USER_ATTR_STAR_MATCHED) ==
924                ACI_USER_ATTR_STAR_MATCHED;
925      }
926    
927      /**
928       * Return true if the evaluating ACI contained a targetattr all
929       * operational attributes rule match.
930       *
931       * @return  True if the above condition was seen.
932       **/
933        public boolean hasAllOpAttributes() {
934        return (evalAllAttributes & ACI_OP_ATTR_PLUS_MATCHED) ==
935                ACI_OP_ATTR_PLUS_MATCHED;
936      }
937    
938      /**
939       * {@inheritDoc}
940       */
941      public void clearEvalAttributes(int v) {
942        if(v == 0)
943          evalAllAttributes=0;
944        else
945          evalAllAttributes &= ~v;
946      }
947    }