/*
*
* * This file is part of the Hesperides distribution.
* * (https://github.com/voyages-sncf-technologies/hesperides)
* * Copyright (c) 2016 VSCT.
* *
* * Hesperides is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as
* * published by the Free Software Foundation, version 3.
* *
* * Hesperides is distributed in the hope that it will be useful, but
* * WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* * General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
package com.vsct.dt.hesperides.resources;
import com.google.common.collect.Lists;
import com.vsct.dt.hesperides.applications.*;
import com.vsct.dt.hesperides.exception.runtime.ForbiddenOperationException;
import com.vsct.dt.hesperides.exception.runtime.MissingResourceException;
import com.vsct.dt.hesperides.security.UserContext;
import com.vsct.dt.hesperides.templating.models.HesperidesPropertiesModel;
import com.vsct.dt.hesperides.templating.models.IterablePropertyModel;
import com.vsct.dt.hesperides.templating.models.KeyValuePropertyModel;
import com.vsct.dt.hesperides.templating.models.Property;
import com.vsct.dt.hesperides.templating.platform.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
/**
* Created by william_montaz on 27/02/2015.
*/
public class PermissionAwareApplicationsProxy implements Applications {
private final ApplicationsAggregate applicationsAggregate;
private final UserContext userContext;
public PermissionAwareApplicationsProxy(final ApplicationsAggregate applicationsAggregate, final UserContext userContext) {
this.applicationsAggregate = applicationsAggregate;
this.userContext = userContext;
}
@Override
public Optional<ApplicationData> getApplication(final String applicationName) {
//No security needed to read informations
return this.applicationsAggregate.getApplication(applicationName);
}
@Override
public Optional<PlatformData> getPlatform(final PlatformKey platformKey) {
//No security needed to read informations
return this.applicationsAggregate.getPlatform(platformKey);
}
@Override
public Optional<TimeStampedPlatformData> getPlatform(final PlatformKey platformKey, final long timestamp) {
//No security needed to read informations
return this.applicationsAggregate.getPlatform(platformKey, timestamp);
}
@Override
public PlatformData createPlatform(final PlatformData platform) {
if (platform.isProduction() && !userContext.getCurrentUser().isProdUser()){
throw new ForbiddenOperationException("Creating a production platform is reserved to production role");
}
return this.applicationsAggregate.createPlatform(platform);
}
@Override
public PlatformData createPlatformFromExistingPlatform(final PlatformData platform, final PlatformKey fromPlatformKey) {
if (platform.isProduction() && !userContext.getCurrentUser().isProdUser()) {
throw new ForbiddenOperationException("Creating a production platform is reserved to production role");
}
final Optional<PlatformData> fromPlatform = this.applicationsAggregate.getPlatform(fromPlatformKey);
if (fromPlatform.isPresent() && fromPlatform.get().isProduction() && !userContext.getCurrentUser().isProdUser()){
throw new ForbiddenOperationException("Creating a platform from a production platform is reserved to production role");
}
return this.applicationsAggregate.createPlatformFromExistingPlatform(platform, fromPlatformKey);
}
@Override
public PlatformData updatePlatform(final PlatformData platform, final boolean isCopyingPropertiesForUpdatedModules) {
PlatformData existingPlatform = this.applicationsAggregate.getPlatform(platform.getKey()).orElseThrow(() -> new MissingResourceException("Cannot check permissions for "+platform));
if (existingPlatform.isProduction() && !userContext.getCurrentUser().isProdUser()){
throw new ForbiddenOperationException("Updating a production platform is reserved to production role");
}
if (platform.isProduction() && !userContext.getCurrentUser().isProdUser()){
throw new ForbiddenOperationException("Upgrading a platform to production is reserved to production role");
}
return this.applicationsAggregate.updatePlatform(platform, isCopyingPropertiesForUpdatedModules);
}
@Override
public PropertiesData getProperties(final PlatformKey platformKey, final String path) {
//No security needed to read informations
return this.applicationsAggregate.getProperties(platformKey, path);
}
@Override
public PropertiesData getProperties(final PlatformKey platformKey, final String path, final long timestamp) {
//No security needed to read informations
return this.applicationsAggregate.getProperties(platformKey, path, timestamp);
}
@Override
public PropertiesData getSecuredProperties(final PlatformKey platformKey, final String path, final HesperidesPropertiesModel model) {
final PlatformData platform = this.applicationsAggregate.getPlatform(platformKey).orElseThrow(() -> new MissingResourceException("Cannot " +
"check permissions for "+ platformKey));
final PropertiesData properties = getProperties(platformKey, path);
if (platform.isProduction() && !userContext.getCurrentUser().isProdUser()) {
return hideProperties(properties, model);
}
return properties;
}
@Override
public PropertiesData getSecuredProperties(final PlatformKey platformKey, final String path, final long timestamp,
final HesperidesPropertiesModel model) {
final PlatformData platform = this.applicationsAggregate.getPlatform(platformKey).orElseThrow(() -> new MissingResourceException("Cannot " +
"check permissions for "+ platformKey));
final PropertiesData properties = getProperties(platformKey, path, timestamp);
if (platform.isProduction() && !userContext.getCurrentUser().isProdUser()) {
return hideProperties(properties, model);
}
return properties;
}
@Override
public PropertiesData createOrUpdatePropertiesInPlatform(final PlatformKey platformKey, final String path,
final PropertiesData properties, final long platformVersionID, final String comment) {
final PlatformData existingPlatform = this.applicationsAggregate.getPlatform(platformKey).orElseThrow(() -> new MissingResourceException
("Cannot check permissions for "+ platformKey));
if(existingPlatform.isProduction() && !userContext.getCurrentUser().isProdUser()){
throw new ForbiddenOperationException("Updating a production platform is reserved to production role");
}
return this.applicationsAggregate.createOrUpdatePropertiesInPlatform(platformKey, path, properties, platformVersionID, comment);
}
@Override
public InstanceModel getInstanceModel(final PlatformKey platformKey, final String instanceName) {
//No security needed to read informations
return this.applicationsAggregate.getInstanceModel(platformKey, instanceName);
}
@Override
public Collection<PlatformData> getAllPlatforms() {
return this.applicationsAggregate.getAllPlatforms();
}
@Override
public void delete(final PlatformKey key) {
final PlatformData existingPlatform = this.applicationsAggregate.getPlatform(key).orElseThrow(() -> new MissingResourceException("Cannot " +
"check permissions for "+key));
if(existingPlatform.isProduction() && !userContext.getCurrentUser().isProdUser()){
throw new ForbiddenOperationException("Deleting a production platform is reserved to production role");
}
this.applicationsAggregate.delete(key);
}
@Override
public long takeSnapshot(final PlatformKey key) {
final PlatformData existingPlatform = this.applicationsAggregate.getPlatform(key).orElseThrow(() -> new MissingResourceException("Cannot " +
"check permissions for "+key));
if (existingPlatform.isProduction() && !userContext.getCurrentUser().isProdUser()) {
throw new ForbiddenOperationException("Snapshoting a production platform is reserved to production role");
}
return this.applicationsAggregate.takeSnapshot(key);
}
@Override
public List<Long> getSnapshots(final PlatformKey key) {
return this.applicationsAggregate.getSnapshots(key);
}
@Override
public PlatformData restoreSnapshot(final PlatformKey key, final long timestamp) {
PlatformData existingPlatform = this.applicationsAggregate.getPlatform(key).orElseThrow(() -> new MissingResourceException("Cannot check permissions for "+key));
if (existingPlatform.isProduction() && !userContext.getCurrentUser().isProdUser()) {
throw new ForbiddenOperationException("Restoring snapshot for a production platform is reserved to production role");
}
return this.applicationsAggregate.restoreSnapshot(key, timestamp);
}
/**
* Hides password field in valuations.
*
* @param valorisations : the valuations
* @param model : the model of thes valuations
* @return the valuations with hidden password fields
*/
private Set<ValorisationData> hideValorisations(final Set<ValorisationData> valorisations, final Set<Property> model) {
final Set<ValorisationData> hidden = new HashSet<>();
for (ValorisationData val : valorisations) {
Optional<Property> optModel = model.stream()
.filter(property -> property.getName().trim().equals(val.getName().trim()))
.findFirst();
if (optModel.isPresent()) {
final Property _model = optModel.get();
if (val instanceof KeyValueValorisationData) {
final KeyValueValorisationData _val = (KeyValueValorisationData) val;
if (_model.isPassword()) {
hidden.add( new KeyValueValorisationData(_val.getName(), "********"));
} else {
hidden.add( new KeyValueValorisationData(_val.getName(), _val.getValue()));
}
} else {
// iterable
hidden.add( hideIterableValorisation((IterableValorisationData) val, (IterablePropertyModel) _model));
}
}
}
return hidden;
}
/**
* Hides password fields of a iterable item
* @param item : the item
* @param model : the model of the item
* @return the item with hidden fields
*/
private IterableValorisationData.IterableValorisationItemData hideItem(
final IterableValorisationData.IterableValorisationItemData item, final IterablePropertyModel model) {
final Set<ValorisationData> values = hideValorisations(item.getValues(), model.getFields());
final IterableValorisationData.IterableValorisationItemData hiddenItem
= new IterableValorisationData.IterableValorisationItemData(item.getTitle(), values);
return hiddenItem;
}
/**
* Hides password fields of an iterable valuation
* @param iterable : the iterable property
* @param model : the model of the property
* @return the iterable property with hidden fields
*/
private IterableValorisationData hideIterableValorisation (final IterableValorisationData iterable,
final IterablePropertyModel model) {
final List<IterableValorisationData.IterableValorisationItemData> items = Lists.newArrayList();
for (IterableValorisationData.IterableValorisationItemData item : iterable.getIterableValorisationItems()) {
items.add(hideItem(item, model));
}
final IterableValorisationData hidden = new IterableValorisationData(iterable.getName(), items);
return hidden;
}
/**
* Hiddes password fields of properties
*
* @param properties : the properties
* @param model : the model
* @return the properties with password fields
*/
private PropertiesData hideProperties(final PropertiesData properties, final HesperidesPropertiesModel model) {
// 1 - Hidding password fields for simple properties
final Set<KeyValueValorisationData> keyValueProperties = new HashSet<>();
final Set<KeyValuePropertyModel> keyValuePropertyModels = model.getKeyValueProperties();
properties.getKeyValueProperties().stream().forEach(keyValueValorisation -> {
// get the model of this property, this is optional because of the global properties has don't have model
final Optional<KeyValuePropertyModel> kvModel = keyValuePropertyModels.stream().filter(keyValuePropertyModel -> keyValuePropertyModel
.getName().trim().equals(keyValueValorisation.getName().trim())).findFirst();
if (kvModel.isPresent()){
if (kvModel.get().isPassword()) {
keyValueProperties.add(new KeyValueValorisationData(keyValueValorisation.getName(), "********"));
} else {
keyValueProperties.add(keyValueValorisation);
}
} else {
keyValueProperties.add(keyValueValorisation);
}
});
// 2 - Hidding password for iterable properties
final Set<IterableValorisationData> iterableProperties = new HashSet<>();
final Set<IterablePropertyModel> iterablePropertyModels = model.getIterableProperties();
for (ValorisationData val : properties.getIterableProperties()) {
final Optional<IterablePropertyModel> subModel = iterablePropertyModels.stream().filter(iterablePropertyModel -> iterablePropertyModel
.getName().trim().equals(val.getName().trim())).findFirst();
if (subModel.isPresent()) {
iterableProperties.add(hideIterableValorisation((IterableValorisationData) val, subModel.get()));
}
}
// 3 - Return the hidden properties
return new PropertiesData(keyValueProperties, iterableProperties);
}
}