From cd8c8bd4e9dfe340942ac21455388bddfd2af986 Mon Sep 17 00:00:00 2001 From: "redmitry@list.ru" Date: Wed, 28 Oct 2020 21:25:04 +0100 Subject: [PATCH] protect Challenge collection --- .../openebench/rest/OpenEBenchService.java | 39 +++++ .../elixir/openebench/rest/dao/Database.java | 165 ++++++++++++++++-- .../inb/elixir/openebench/rest/dao/Roles.java | 39 +++++ 3 files changed, 228 insertions(+), 15 deletions(-) create mode 100644 src/main/java/es/bsc/inb/elixir/openebench/rest/dao/Roles.java diff --git a/src/main/java/es/bsc/inb/elixir/openebench/rest/OpenEBenchService.java b/src/main/java/es/bsc/inb/elixir/openebench/rest/OpenEBenchService.java index eca57bc..5070abe 100644 --- a/src/main/java/es/bsc/inb/elixir/openebench/rest/OpenEBenchService.java +++ b/src/main/java/es/bsc/inb/elixir/openebench/rest/OpenEBenchService.java @@ -286,4 +286,43 @@ public class OpenEBenchService { return Response.ok(dataset, MediaType.APPLICATION_JSON).build(); } + + @GET + @Path("/Challenge") + @PermitAll + @Produces(MediaType.APPLICATION_JSON) + public Response getChallenges(@Context SecurityContext sc) { + + StreamingOutput stream = (OutputStream out) -> { + try (Writer writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"))) { + dao.getChallenges(writer, sc); + } catch(Exception ex) { + Logger.getLogger(OpenEBenchService.class.getName()).log(Level.SEVERE, null, ex); + } + }; + return Response.ok(stream, MediaType.APPLICATION_JSON).build(); + } + + @GET + @Path("/Challenge/{id : .*}") + @PermitAll + @Produces(MediaType.APPLICATION_JSON) + public Response getChallenges(@Context SecurityContext sc, + @PathParam("id") + @Parameter(description = "challenge id", + example = "OEBX00200001FO") + @Encoded final String id) { + + final String challenge = dao.getChallenge(id, sc); + + if (challenge == null) { + return Response.status(Status.NOT_FOUND).build(); + } + + if ("{}".equals(challenge)) { + return Response.status(Status.UNAUTHORIZED).build(); + } + + return Response.ok(challenge, MediaType.APPLICATION_JSON).build(); + } } diff --git a/src/main/java/es/bsc/inb/elixir/openebench/rest/dao/Database.java b/src/main/java/es/bsc/inb/elixir/openebench/rest/dao/Database.java index 5238090..5ae8a22 100644 --- a/src/main/java/es/bsc/inb/elixir/openebench/rest/dao/Database.java +++ b/src/main/java/es/bsc/inb/elixir/openebench/rest/dao/Database.java @@ -1,3 +1,28 @@ +/** + * ***************************************************************************** + * Copyright (C) 2020 ELIXIR ES, Spanish National Bioinformatics Institute (INB) + * and Barcelona Supercomputing Center (BSC) + * + * Modifications to the initial code base are copyright of their respective + * authors, or their employers as appropriate. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + ***************************************************************************** + */ + package es.bsc.inb.elixir.openebench.rest.dao; import com.mongodb.DBCollection; @@ -172,6 +197,66 @@ public class Database { } } + public String getChallenge(final String id, final SecurityContext sc) { + try { + final MongoDatabase mdb = mc.getDatabase(uri.getDatabase()); + final MongoCollection challenges = mdb.getCollection("Challenge"); + final MongoCollection events = mdb.getCollection("BenchmarkingEvent"); + + final Document challenge = challenges.find(Filters.eq("_id", id)).first(); + if (challenge != null && checkChallengeAccess(challenge, sc, events)) { + challenge.remove("@provenance"); + return challenge.toJson(); + } + return "{}"; + } catch(Exception ex) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex); + } + + return null; + } + + public void getChallenges(final Writer writer, final SecurityContext sc) { + try { + MongoDatabase mdb = mc.getDatabase(uri.getDatabase()); + final MongoCollection challenges = mdb.getCollection("Challenge"); + final MongoCollection events = mdb.getCollection("BenchmarkingEvent"); + + final JsonWriter jwriter = new ReusableJsonWriter(writer); + try { + jwriter.writeStartArray(); + + final DocumentCodec codec = new DocumentCodec() { + @Override + public void encode(BsonWriter writer, + Document document, + EncoderContext encoderContext) { + super.encode(jwriter, document, encoderContext); + } + }; + + final Map mcommunities = new HashMap<>(); + + FindIterable iter = challenges.find(); + try (MongoCursor cursor = iter.iterator()) { + loop: + while (cursor.hasNext()) { + final Document challenge = cursor.next(); + if (checkChallengeAccess(challenge, sc, events, mcommunities)) { + challenge.remove("@provenance"); + challenge.toJson(codec); + } + } + } + } finally { + jwriter.writeEndArray(); + jwriter.close(); + } + } catch(Exception ex) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex); + } + } + public String getDataset(final String id, final SecurityContext sc) { try { final MongoDatabase mdb = mc.getDatabase(uri.getDatabase()); @@ -240,6 +325,38 @@ public class Database { } } + private boolean checkChallengeAccess(final Document challenge, final SecurityContext sc, + final MongoCollection events) { + + return checkChallengeAccess(challenge, sc, events, null); + } + + private boolean checkChallengeAccess(final Document challenge, final SecurityContext sc, + final MongoCollection events, final Map mcommunities) { + + if (sc.isUserInRole(Roles.ADMIN)) { + return true; + } + + final String challenge_id = challenge.getString("_id"); + + if (sc.isUserInRole(Roles.CONTRIBUTOR + ":" + challenge_id) || + sc.isUserInRole(Roles.MANAGER + ":" + challenge_id)) { + return true; + } + + final String community_id = getCommunityId(challenge, events); + if (community_id == null) { + return false; + } + + if (mcommunities != null) { + mcommunities.put(challenge_id, community_id); + } + + return sc.isUserInRole(Roles.OWNER + ":" + community_id); + } + /** * Check the access to the dataset according provided security context. * @@ -252,9 +369,13 @@ public class Database { * @return true if access is granted, false otherwise */ private boolean checkDatasetAccess(final Document dataset, final SecurityContext sc, - final MongoCollection challenges, MongoCollection events, + final MongoCollection challenges, final MongoCollection events, final Map mcommunities) { + if (sc.isUserInRole(Roles.ADMIN)) { + return true; + } + final String visibility = dataset.getString("visibility"); if ("public".equals(visibility)) { return true; @@ -262,8 +383,8 @@ public class Database { final List challenge_ids = dataset.get("challenge_ids", List.class); for (String challenge_id : challenge_ids) { if (("participant".equals(visibility) && - sc.isUserInRole("contributor:" + challenge_id)) || - sc.isUserInRole("manager:" + challenge_id)) { + sc.isUserInRole(Roles.CONTRIBUTOR + ":" + challenge_id)) || + sc.isUserInRole(Roles.MANAGER + ":" + challenge_id)) { return true; } String community_id = mcommunities.get(challenge_id); @@ -272,28 +393,43 @@ public class Database { if (challenge == null) { continue; } - final String benchmarking_event_id = challenge.getString("benchmarking_event_id"); - if (benchmarking_event_id == null) { - continue; - } - final Document event = events.find(Filters.eq("_id", benchmarking_event_id)).first(); - if (event == null) { - continue; - } - community_id = event.getString("community_id"); + community_id = getCommunityId(challenge, events); if (community_id == null) { continue; } mcommunities.put(challenge_id, community_id); } - if (sc.isUserInRole("owner:" + community_id)) { + if (sc.isUserInRole(Roles.OWNER + ":" + community_id)) { return true; } } } return false; } - + + /** + * Find the 'Community' associated to the 'Challenge'. + * + * @param challenge 'Challenge' JSON document + * @param events MongoDB 'BenchmarikingEvent' collection + * + * @return either the 'community_id' or 'null' + */ + private String getCommunityId(final Document challenge, final MongoCollection events) { + + final String benchmarking_event_id = challenge.getString("benchmarking_event_id"); + if (benchmarking_event_id == null) { + return null; + } + + final Document event = events.find(Filters.eq("_id", benchmarking_event_id)).first(); + if (event == null) { + return null; + } + + return event.getString("community_id"); + } + public static class ReusableJsonWriter extends JsonWriter { public ReusableJsonWriter(Writer writer) { @@ -305,5 +441,4 @@ public class Database { return true; } } - } diff --git a/src/main/java/es/bsc/inb/elixir/openebench/rest/dao/Roles.java b/src/main/java/es/bsc/inb/elixir/openebench/rest/dao/Roles.java new file mode 100644 index 0000000..ab1a910 --- /dev/null +++ b/src/main/java/es/bsc/inb/elixir/openebench/rest/dao/Roles.java @@ -0,0 +1,39 @@ +/** + * ***************************************************************************** + * Copyright (C) 2020 ELIXIR ES, Spanish National Bioinformatics Institute (INB) + * and Barcelona Supercomputing Center (BSC) + * + * Modifications to the initial code base are copyright of their respective + * authors, or their employers as appropriate. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + ***************************************************************************** + */ + +package es.bsc.inb.elixir.openebench.rest.dao; + +/** + * @author Dmitry Repchevsky + */ + +public final class Roles { + + public final static String ADMIN = "admin:oeb"; + public final static String OWNER = "owner"; + public final static String MANAGER = "manager"; + public final static String CONTRIBUTOR = "contributor"; + public final static String PARTICIPANT = "participant"; +} -- 2.24.1