View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  
22  package org.opencastproject.authorization.xacml.manager.impl;
23  
24  import org.opencastproject.authorization.xacml.manager.api.AclService;
25  import org.opencastproject.authorization.xacml.manager.api.AclServiceException;
26  import org.opencastproject.authorization.xacml.manager.api.ManagedAcl;
27  import org.opencastproject.elasticsearch.api.SearchIndexException;
28  import org.opencastproject.elasticsearch.api.SearchResult;
29  import org.opencastproject.elasticsearch.api.SearchResultItem;
30  import org.opencastproject.elasticsearch.index.ElasticsearchIndex;
31  import org.opencastproject.elasticsearch.index.objects.event.Event;
32  import org.opencastproject.elasticsearch.index.objects.event.EventSearchQuery;
33  import org.opencastproject.elasticsearch.index.objects.series.Series;
34  import org.opencastproject.elasticsearch.index.objects.series.SeriesSearchQuery;
35  import org.opencastproject.security.api.AccessControlList;
36  import org.opencastproject.security.api.Organization;
37  import org.opencastproject.security.api.SecurityService;
38  import org.opencastproject.security.api.User;
39  import org.opencastproject.util.NotFoundException;
40  
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  
44  import java.util.List;
45  import java.util.Optional;
46  import java.util.function.Function;
47  
48  /** Organization bound impl. */
49  public final class AclServiceImpl implements AclService {
50    /** Logging utility */
51    private static final Logger logger = LoggerFactory.getLogger(AclServiceImpl.class);
52  
53    /** Context */
54    private final Organization organization;
55  
56    /** Service dependencies */
57    private final AclDb aclDb;
58    private final SecurityService securityService;
59  
60    /** The Elasticsearch indices */
61    protected ElasticsearchIndex index;
62  
63    public AclServiceImpl(Organization organization, AclDb aclDb, ElasticsearchIndex index,
64            SecurityService securityService) {
65      this.organization = organization;
66      this.aclDb = aclDb;
67      this.index = index;
68      this.securityService = securityService;
69    }
70  
71    @Override
72    public List<ManagedAcl> getAcls() {
73      return aclDb.getAcls(organization);
74    }
75  
76    @Override
77    public Optional<ManagedAcl> getAcl(long id) {
78      return aclDb.getAcl(organization, id);
79    }
80  
81    @Override
82    public Optional<ManagedAcl> getAcl(String name) {
83      return aclDb.getAcl(organization, name);
84    }
85  
86    @Override
87    public boolean updateAcl(ManagedAcl acl) {
88      Optional<ManagedAcl> oldName = getAcl(acl.getId());
89      boolean updateAcl = aclDb.updateAcl(acl);
90      if (updateAcl) {
91        if (oldName.isPresent() && !(oldName.get().getName().equals(acl.getName()))) {
92          User user = securityService.getUser();
93          updateAclInIndex(oldName.get().getName(), acl.getName(), index, organization.getId(), user);
94        }
95      }
96      return updateAcl;
97    }
98  
99    @Override
100   public Optional<ManagedAcl> createAcl(AccessControlList acl, String name) {
101     // we don't need to update the Elasticsearch indices in this case
102     return aclDb.createAcl(organization, acl, name);
103   }
104 
105   @Override
106   public boolean deleteAcl(long id) throws AclServiceException, NotFoundException {
107     Optional<ManagedAcl> deletedAcl = getAcl(id);
108     if (aclDb.deleteAcl(organization, id)) {
109       if (deletedAcl.isPresent()) {
110         User user = securityService.getUser();
111         removeAclFromIndex(deletedAcl.get().getName(), index, organization.getId(), user);
112       }
113       return true;
114     }
115     throw new NotFoundException("Managed acl with id " + id + " not found.");
116   }
117 
118   /**
119    * Update the Managed ACL in the events and series in the Elasticsearch index.
120    *
121    * @param currentAclName
122    *         the current name of the managed acl
123    * @param newAclName
124    *         the new name of the managed acl
125    * @param index
126    *         the index to update
127    * @param orgId
128    *         the organization the managed acl belongs to
129    * @param user
130    *         the current user
131    */
132   private void updateAclInIndex(String currentAclName, String newAclName, ElasticsearchIndex index, String orgId,
133           User user) {
134     logger.debug("Update the events to change the managed acl name from '{}' to '{}'.", currentAclName, newAclName);
135     updateManagedAclForEvents(currentAclName, Optional.of(newAclName), index, orgId, user);
136 
137     logger.debug("Update the series to change the managed acl name from '{}' to '{}'.", currentAclName, newAclName);
138     updateManagedAclForSeries(currentAclName, Optional.of(newAclName), index, orgId, user);
139   }
140 
141   /**
142    * Remove the Managed ACL from the events and series in the Elasticsearch index.
143    *
144    * @param currentAclName
145    *         the current name of the managed acl
146    * @param index
147    *         the index to update
148    * @param orgId
149    *         the organization the managed acl belongs to
150    * @param user
151    *         the current user
152    */
153   private void removeAclFromIndex(String currentAclName, ElasticsearchIndex index, String orgId,
154           User user) {
155     logger.debug("Update the events to remove the managed acl name '{}'.", currentAclName);
156     updateManagedAclForEvents(currentAclName, Optional.empty(), index, orgId, user);
157 
158     logger.debug("Update the series to remove the managed acl name '{}'.", currentAclName);
159     updateManagedAclForSeries(currentAclName, Optional.empty(), index, orgId, user);
160   }
161 
162   /**
163    * Update or remove the Managed Acl for the series in the Elasticsearch index.
164    *
165    * @param currentAclName
166    *         the current name of the managed acl
167    * @param newAclNameOpt
168    * @param index
169    *         the index to update
170    * @param orgId
171    *         the organization the managed acl belongs to
172    * @param user
173    *         the current user
174    */
175   private void updateManagedAclForSeries(String currentAclName, Optional<String> newAclNameOpt,
176           ElasticsearchIndex index, String orgId, User user) {
177     SearchResult<Series> result;
178     try {
179       result = index.getByQuery(new SeriesSearchQuery(orgId, user).withoutActions()
180               .withManagedAcl(currentAclName));
181     } catch (SearchIndexException e) {
182       logger.error("Unable to find the series in org '{}' with current managed acl name '{}'", orgId, currentAclName,
183               e);
184       return;
185     }
186 
187     for (SearchResultItem<Series> seriesItem : result.getItems()) {
188       String seriesId = seriesItem.getSource().getIdentifier();
189 
190       Function<Optional<Series>, Optional<Series>> updateFunction = (Optional<Series> seriesOpt) -> {
191         if (seriesOpt.isPresent() && seriesOpt.get().getManagedAcl().equals(currentAclName)) {
192           Series series = seriesOpt.get();
193           series.setManagedAcl(newAclNameOpt.orElse(null));
194           return Optional.of(series);
195         }
196         return Optional.empty();
197       };
198 
199       try {
200         index.addOrUpdateSeries(seriesId, updateFunction, orgId, user);
201       } catch (SearchIndexException e) {
202         if (newAclNameOpt.isPresent()) {
203           logger.warn("Unable to update series'{}' from current managed acl '{}' to new managed acl name '{}'",
204                   seriesId, currentAclName, newAclNameOpt.get(), e);
205         } else {
206           logger.warn("Unable to update series '{}' to remove managed acl '{}'", seriesId, currentAclName, e);
207         }
208       }
209     }
210   }
211 
212   /**
213    * Update or remove the Managed Acl for the events in the Elasticsearch index.
214    *
215    * @param currentAclName
216    *         the current name of the managed acl
217    * @param newAclNameOpt
218    * @param index
219    *         the index to update
220    * @param orgId
221    *         the organization the managed acl belongs to
222    * @param user
223    *         the current user
224    */
225   private void updateManagedAclForEvents(String currentAclName, Optional<String> newAclNameOpt,
226           ElasticsearchIndex index, String orgId, User user) {
227     SearchResult<Event> result;
228     try {
229       result = index.getByQuery(new EventSearchQuery(orgId, user).withoutActions()
230               .withManagedAcl(currentAclName));
231     } catch (SearchIndexException e) {
232       logger.error("Unable to find the events in org '{}' with current managed acl name '{}' for event",
233               orgId, currentAclName, e);
234       return;
235     }
236 
237     for (SearchResultItem<Event> eventItem : result.getItems()) {
238       String eventId = eventItem.getSource().getIdentifier();
239 
240       Function<Optional<Event>, Optional<Event>> updateFunction = (Optional<Event> eventOpt) -> {
241         if (eventOpt.isPresent() && eventOpt.get().getManagedAcl().equals(currentAclName)) {
242           Event event = eventOpt.get();
243           event.setManagedAcl(newAclNameOpt.orElse(null));
244           return Optional.of(event);
245         }
246         return Optional.empty();
247       };
248 
249       try {
250         index.addOrUpdateEvent(eventId, updateFunction, orgId, user);
251       } catch (SearchIndexException e) {
252         if (newAclNameOpt.isPresent()) {
253           logger.warn(
254                   "Unable to update event '{}' from current managed acl '{}' to new managed acl name '{}'",
255                   eventId, currentAclName, newAclNameOpt.get(), e);
256         } else {
257           logger.warn("Unable to update event '{}' to remove managed acl '{}'", eventId, currentAclName, e);
258         }
259       }
260     }
261   }
262 }