Skip to content
Snippets Groups Projects
Commit 4e5340b2 authored by brinn's avatar brinn
Browse files

[BIS-137] Implement a more secure ExperimentListPredicate. The new code checks...

[BIS-137] Implement a more secure ExperimentListPredicate. The new code checks all security-relevant aspects of the Experiment object, rather than just checking the experiment identifier.

SVN: 26191
parent fc548d8e
No related branches found
No related tags found
No related merge requests found
/*
* Copyright 2010 ETH Zuerich, CISD
*
* 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 ch.systemsx.cisd.openbis.generic.server.authorization.predicate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.lemnik.eodsql.BaseQuery;
import net.lemnik.eodsql.QueryTool;
import net.lemnik.eodsql.Select;
import ch.systemsx.cisd.common.exceptions.AuthorizationFailureException;
import ch.systemsx.cisd.common.exceptions.Status;
import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.LongArrayMapper;
import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.StringArrayMapper;
import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Experiment;
import ch.systemsx.cisd.openbis.generic.shared.authorization.RoleWithIdentifier;
import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.ShouldFlattenCollections;
import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.AbstractSpacePredicate;
import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
import ch.systemsx.cisd.openbis.generic.shared.util.SpaceCodeHelper;
/**
* A predicate for lists of entities of {@link Experiment}s.
* <p>
* <i>This is an internal class. Do not use it as a user of the API.</i>
*
* @author Bernd Rinn
*/
@ShouldFlattenCollections(value = false)
public class ExperimentListPredicate extends AbstractSpacePredicate<List<Experiment>>
{
//
// AbstractPredicate
//
@Override
public String getCandidateDescription()
{
return "experiment";
}
@Override
protected Status doEvaluation(PersonPE person, List<RoleWithIdentifier> allowedRoles,
List<Experiment> experiments)
{
// All fields relevant for authorization are expected to be filled:
// - technical id
// - permanent id
// - identifier
final List<Long> ids = new ArrayList<Long>(experiments.size());
final List<String> permIds = new ArrayList<String>(experiments.size());
for (Experiment experiment : experiments)
{
if (experiment.getId() == null)
{
throw new AuthorizationFailureException("id is undefined.");
}
ids.add(experiment.getId());
if (experiment.getPermId() == null)
{
throw new AuthorizationFailureException("permId is undefined.");
}
permIds.add(experiment.getPermId());
final SpaceIdentifier spaceIdentifier =
new ExperimentIdentifierFactory(experiment.getIdentifier()).createIdentifier();
final String spaceCode = SpaceCodeHelper.getSpaceCode(person, spaceIdentifier);
final DatabaseInstancePE databaseInstance = getDatabaseInstance(spaceIdentifier);
final Status status =
evaluate(person, allowedRoles, databaseInstance, spaceCode);
if (Status.OK.equals(status) == false)
{
return status;
}
}
for (Long spaceId : getExperimentSpaceIds(ids, permIds))
{
final Status status = evaluate(person, allowedRoles, spaceId);
if (Status.OK.equals(status) == false)
{
return status;
}
}
return Status.OK;
}
private final static int ARRAY_SIZE_LIMIT = 999;
interface IExperimentToSpaceQuery extends BaseQuery
{
@Select(sql = "select distinct space_id from projects p left join experiments e on e.proj_id = p.id "
+ "where id = any(?{1}) union "
+ "select distinct space_id from projects p left join experiments e on e.proj_id = p.id "
+ "where perm_id = any(?{2})", parameterBindings =
{ LongArrayMapper.class, StringArrayMapper.class })
public List<Long> getExperimentSpaceIds(long[] experimentIds, String[] experimentPermIds);
}
private Collection<Long> getExperimentSpaceIds(final List<Long> ids, final List<String> permIds)
{
if (ids.size() != permIds.size())
{
throw new IllegalArgumentException("Expect to get the same number of ids and permIds.");
}
final int size = ids.size();
if (size == 0)
{
return Collections.emptyList();
}
final IExperimentToSpaceQuery query =
QueryTool.getQuery(authorizationDataProvider.getConnection(),
IExperimentToSpaceQuery.class);
if (size > ARRAY_SIZE_LIMIT)
{
final Set<Long> spaceIds = new HashSet<Long>(size);
for (int startIdx = 0; startIdx < size; startIdx += ARRAY_SIZE_LIMIT)
{
final List<Long> idSubList = ids.subList(startIdx,
Math.min(size, startIdx + ARRAY_SIZE_LIMIT));
final List<String> permIdSubList = permIds.subList(startIdx,
Math.min(size, startIdx + ARRAY_SIZE_LIMIT));
spaceIds.addAll(query.getExperimentSpaceIds(toArray(idSubList),
permIdSubList.toArray(new String[permIdSubList.size()])));
}
return spaceIds;
} else
{
return query.getExperimentSpaceIds(toArray(ids), permIds.toArray(new String[size]));
}
}
private long[] toArray(List<Long> list)
{
final long[] result = new long[list.size()];
for (int i = 0; i < result.length; ++i)
{
result[i] = list.get(i);
}
return result;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment