View Javadoc

1   /*
2    * Copyright 2008 Members of the EGEE Collaboration.
3    * Copyright 2008 University Corporation for Advanced Internet Development, Inc.
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.opensaml.xacml.ctx.provider;
19  
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.Comparator;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.Map;
26  import java.util.Set;
27  import java.util.TreeSet;
28  import java.util.concurrent.locks.Lock;
29  import java.util.concurrent.locks.ReentrantReadWriteLock;
30  
31  import org.opensaml.xacml.ctx.DecisionType.DECISION;
32  import org.opensaml.xacml.policy.EffectType;
33  import org.opensaml.xacml.policy.ObligationType;
34  import org.opensaml.xacml.policy.ObligationsType;
35  
36  /** A service for evaluating the obligations within a context. */
37  public class ObligationService {
38  
39      /** Read/write lock around the registered obligation handlers. */
40      private ReentrantReadWriteLock rwLock;
41  
42      /** Registered obligation handlers. */
43      private Set<BaseObligationHandler> obligationHandlers;
44  
45      /** Constructor. */
46      public ObligationService() {
47          rwLock = new ReentrantReadWriteLock(true);
48          obligationHandlers = new TreeSet<BaseObligationHandler>(new ObligationHandlerComparator());
49      }
50  
51      /**
52       * Gets the registered obligation handlers.
53       * 
54       * @return registered obligation handlers
55       */
56      public Set<BaseObligationHandler> getObligationHandlers() {
57          return Collections.unmodifiableSet(obligationHandlers);
58      }
59  
60      /**
61       * Adds an obligation handler to the list of registered handlers
62       * 
63       * This method waits until a write lock is obtained for the set of registered obligation handlers.
64       * 
65       * @param handler the handler to add to the list of registered handlers.
66       */
67      public void addObligationhandler(BaseObligationHandler handler) {
68          if (handler == null) {
69              return;
70          }
71  
72          Lock writeLock = rwLock.writeLock();
73          writeLock.lock();
74          try {
75              obligationHandlers.add(handler);
76          } finally {
77              writeLock.unlock();
78          }
79      }
80  
81      /**
82       * Adds a collection of obligation handler to the list of registered handlers
83       * 
84       * This method waits until a write lock is obtained for the set of registered obligation handlers.
85       * 
86       * @param handlers the collection of handlers to add to the list of registered handlers.
87       */
88      public void addObligationhandler(Collection<BaseObligationHandler> handlers) {
89          if (handlers == null || handlers.isEmpty()) {
90              return;
91          }
92  
93          Lock writeLock = rwLock.writeLock();
94          writeLock.lock();
95          try {
96              obligationHandlers.addAll(handlers);
97          } finally {
98              writeLock.unlock();
99          }
100     }
101 
102     /**
103      * Removes an obligation handler from the list of registered handlers
104      * 
105      * This method waits until a write lock is obtained for the set of registered obligation handlers.
106      * 
107      * @param handler the handler to remove from the list of registered handlers.
108      */
109     public void removeObligationHandler(BaseObligationHandler handler) {
110         if (handler == null) {
111             return;
112         }
113 
114         Lock writeLock = rwLock.writeLock();
115         writeLock.lock();
116         try {
117             obligationHandlers.remove(handler);
118         } finally {
119             writeLock.unlock();
120         }
121     }
122 
123     /**
124      * Processes the obligations within the effective XACML policy.
125      * 
126      * This method waits until a read lock is obtained for the set of registered obligation handlers.
127      * 
128      * @param context current processing context
129      * 
130      * @throws ObligationProcessingException thrown if there is a problem evaluating an obligation
131      */
132     public void processObligations(ObligationProcessingContext context) throws ObligationProcessingException {
133         Lock readLock = rwLock.readLock();
134         readLock.lock();
135         try {
136             Iterator<BaseObligationHandler> handlerItr = obligationHandlers.iterator();
137             Map<String, ObligationType> effectiveObligations = preprocessObligations(context);
138 
139             BaseObligationHandler handler;
140             while (handlerItr.hasNext()) {
141                 handler = handlerItr.next();
142                 if (effectiveObligations.containsKey(handler.getObligationId())) {
143                     handler.evaluateObligation(context, effectiveObligations.get(handler.getObligationId()));
144                 }
145             }
146         } finally {
147             readLock.unlock();
148         }
149     }
150 
151     /**
152      * Preprocesses the obligations returned within the result. This preprocessing determines the active effect, based
153      * on {@link org.opensaml.xacml.ctx.ResultType#getDecision()}, and creates an index that maps obligation IDs to the
154      * {@link ObligationType} returned by the PDP.
155      * 
156      * @param context current processing context
157      * 
158      * @return preprocessed obligations
159      */
160     protected Map<String, ObligationType> preprocessObligations(ObligationProcessingContext context) {
161         HashMap<String, ObligationType> effectiveObligations = new HashMap<String, ObligationType>();
162 
163         ObligationsType obligations = context.getAuthorizationDecisionResult().getObligations();
164         if (obligations == null || obligations.getObligations() == null) {
165             return effectiveObligations;
166         }
167 
168         EffectType activeEffect;
169         if (context.getAuthorizationDecisionResult().getDecision().getDecision() == DECISION.Permit) {
170             activeEffect = EffectType.Permit;
171         } else {
172             activeEffect = EffectType.Deny;
173         }
174 
175         for (ObligationType obligation : obligations.getObligations()) {
176             if (obligation != null && obligation.getFulfillOn() == activeEffect) {
177                 effectiveObligations.put(obligation.getObligationId(), obligation);
178             }
179         }
180 
181         return effectiveObligations;
182     }
183 
184     /** Comparator used to order obligation handlers by precedence. */
185     private class ObligationHandlerComparator implements Comparator<BaseObligationHandler> {
186 
187         /** {@inheritDoc} */
188         public int compare(BaseObligationHandler o1, BaseObligationHandler o2) {
189             if (o1.getHandlerPrecedence() == o2.getHandlerPrecedence()) {
190                 // If they have the same precedence sort lexigraphically
191                 return o1.getObligationId().compareTo(o2.getObligationId());
192             }
193 
194             if (o1.getHandlerPrecedence() < o2.getHandlerPrecedence()) {
195                 return -1;
196             }
197 
198             return 1;
199         }
200     }
201 }