/*
* Copyright 2015-2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hawkular.inventory.rest.security.accounts;
import static org.hawkular.inventory.api.Action.created;
import static org.hawkular.inventory.api.Action.deleted;
import java.util.HashSet;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.transaction.Transactional;
import org.hawkular.accounts.api.PersonaService;
import org.hawkular.accounts.api.ResourceService;
import org.hawkular.accounts.api.model.Persona;
import org.hawkular.inventory.api.Action;
import org.hawkular.inventory.api.Interest;
import org.hawkular.inventory.api.Inventory;
import org.hawkular.inventory.api.model.AbstractElement;
import org.hawkular.inventory.api.model.Entity;
import org.hawkular.inventory.cdi.DisposingInventory;
import org.hawkular.inventory.cdi.InventoryInitialized;
import org.hawkular.inventory.paths.CanonicalPath;
import org.hawkular.inventory.rest.security.Security;
import rx.Subscription;
/**
* Integrates Accounts Tenants model with Inventory.
* <p>
* Mutation operations must be checked explicitly in the REST classes using the {@link Security} bean and invoking
* one of its {@code can*()} methods. The creation of the security resources associated with the newly created inventory
* entities is handled automagically by this class which does that by observing the mutation events on the Inventory.
*
* @author Lukas Krejci
* @author <a href="https://github.com/ppalaga">Peter Palaga</a>
* @since 0.0.2
*/
@ApplicationScoped
public class SecurityIntegration {
private static final SecurityAccountsLogger log = SecurityAccountsLogger.getLogger(InventorySecurity.class);
@Inject
private ResourceService storage;
@Inject
private PersonaService personas;
private final Set<Subscription> subscriptions = new HashSet<>();
public void start(@Observes InventoryInitialized event) {
Inventory inventory = event.getInventory();
Inventory.types().entityTypes().forEach(et -> install(inventory, et.getElementType()));
}
public void stop(@Observes DisposingInventory event) {
subscriptions.forEach(Subscription::unsubscribe);
subscriptions.clear();
}
private <E extends Entity<?, ?>> void install(Inventory inventory, Class<E> cls) {
subscriptions.add(inventory.observable(Interest.in(cls).being(created()))
.subscribe((e) -> react(e, created())));
subscriptions.add(inventory.observable(Interest.in(cls).being(deleted()))
.subscribe((e) -> react(e, deleted())));
}
@Transactional
public void react(AbstractElement<?, ?> entity, Action<?, ?> action) {
switch (action.asEnum()) {
case CREATED:
createSecurityResource(entity.getPath());
break;
case DELETED:
String stableId = AccountsSecurityUtils.getStableId(entity.getPath());
storage.delete(stableId);
log.debugf("Deleted security entity with stable ID '%s' for entity %s", stableId, entity);
break;
}
}
private org.hawkular.accounts.api.model.Resource createSecurityResource(CanonicalPath path) {
if (!path.isDefined()) {
return null;
}
log.tracef("Creating security entity for %s", path);
String stableId = AccountsSecurityUtils.getStableId(path);
org.hawkular.accounts.api.model.Resource res = storage.get(stableId);
if (res == null) {
org.hawkular.accounts.api.model.Resource parent = createSecurityResource(path.up());
// if the parent is null, it means we're creating a security resource for the tenant - we need to assign
// it an owner. If the parent exists, we need to establish the owner to assign to the current resource
Persona owner = personas.getCurrent();
if (parent != null) {
owner = establishOwner(parent, owner);
}
res = storage.create(stableId, parent, owner);
log.debugf("Created security entity with stable ID '%s' for entity %s", stableId, path);
}
return res;
}
/**
* Establishes the owner. If the owner of the parent is the same as the current user, then create the resource
* as being owner-less, inheriting the owner from the parent.
*/
private Persona establishOwner(org.hawkular.accounts.api.model.Resource resource, Persona current) {
while (resource != null && resource.getPersona() == null) {
resource = resource.getParent();
}
if (resource != null && resource.getPersona().equals(current)) {
current = null;
}
return current;
}
}