diff options
| author | Simon Rettberg | 2015-07-03 16:43:38 +0200 |
|---|---|---|
| committer | Simon Rettberg | 2015-07-03 16:43:38 +0200 |
| commit | 90c159d622f234b99e47293f3ff2a35d64e6f8c9 (patch) | |
| tree | e967412b1464e9e3cad381399d5dd1c596c0bf28 | |
| parent | [server] Refactored permission checking classes a bit (diff) | |
| download | tutor-module-90c159d622f234b99e47293f3ff2a35d64e6f8c9.tar.gz tutor-module-90c159d622f234b99e47293f3ff2a35d64e6f8c9.tar.xz tutor-module-90c159d622f234b99e47293f3ff2a35d64e6f8c9.zip | |
[server] Adapt to API changes, refine permission checking for image version deletion
8 files changed, 252 insertions, 49 deletions
diff --git a/dozentenmodulserver/pom.xml b/dozentenmodulserver/pom.xml index e5ab5ae7..20afc516 100644 --- a/dozentenmodulserver/pom.xml +++ b/dozentenmodulserver/pom.xml @@ -145,7 +145,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>2.2.4</version> + <version>2.3.1</version> <scope>compile</scope> </dependency> </dependencies> diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java index 03ae5dd4..b6e632e6 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java @@ -14,16 +14,19 @@ import org.openslx.bwlp.sat.database.Database; import org.openslx.bwlp.sat.database.mappers.DbImage; import org.openslx.bwlp.sat.fileserv.FileServer; import org.openslx.bwlp.sat.thrift.BinaryListener; -import org.openslx.bwlp.sat.thrift.cache.OperatingSystemList; import org.openslx.bwlp.sat.thrift.cache.OrganizationList; import org.openslx.bwlp.sat.util.Configuration; +import org.openslx.bwlp.sat.util.Json; import org.openslx.bwlp.sat.util.QuickTimer; import org.openslx.bwlp.thrift.iface.ImageSummaryRead; +import org.openslx.bwlp.thrift.iface.NetDirection; +import org.openslx.bwlp.thrift.iface.NetRule; import org.openslx.bwlp.thrift.iface.UserInfo; + public class App { - private static Logger log = Logger.getLogger(App.class); + private static Logger LOGGER = Logger.getLogger(App.class); private static List<Thread> servers = new ArrayList<>(); @@ -35,16 +38,16 @@ public class App { if (args.length != 0 && args[0].equals("debug")) { DEBUG = true; } - log.info("****************************************************************"); - log.info("******************* Starting Application ***********************"); - log.info("****************************************************************"); + LOGGER.info("****************************************************************"); + LOGGER.info("******************* Starting Application ***********************"); + LOGGER.info("****************************************************************"); // get Configuration try { - log.info("Loading configuration"); + LOGGER.info("Loading configuration"); Configuration.load(); } catch (Exception e1) { - log.fatal("Could not load configuration", e1); + LOGGER.fatal("Could not load configuration", e1); System.exit(1); } @@ -54,7 +57,7 @@ public class App { // Start file transfer server if (!FileServer.instance().start()) { - log.error("Could not start internal file server."); + LOGGER.error("Could not start internal file server."); return; } // Start Server @@ -68,9 +71,9 @@ public class App { List<ImageSummaryRead> allVisible; try { allVisible = DbImage.getAllVisible(new UserInfo("bla", "blu", null, null, null), null, 0); - log.info("Got " + allVisible.size()); + LOGGER.info("Got " + allVisible.size()); } catch (SQLException e) { - log.warn("could not test query getallvisible"); + LOGGER.warn("could not test query getallvisible"); } QuickTimer.scheduleAtFixedDelay(new TimerTask() { @Override @@ -78,6 +81,12 @@ public class App { Database.printDebug(); } }, 100, 5000); + NetRule nr = new NetRule(2, NetDirection.OUT, "dsafg", 1336); + String data = Json.serialize(nr); + LOGGER.info(data); + Json.registerThriftClass(NetRule.class); + NetRule nn = Json.deserializeThrift(data, NetRule.class); + LOGGER.info(nn); } // Wait for servers for (Thread wait : servers) { @@ -92,7 +101,7 @@ public class App { } } QuickTimer.cancel(); - log.info(new Date() + " - all Servers shut down, exiting...\n"); + LOGGER.info(new Date() + " - all Servers shut down, exiting...\n"); } } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/Database.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/Database.java index 422db229..446cfbea 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/Database.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/Database.java @@ -44,9 +44,6 @@ public class Database { * @return connection to database, or <code>null</code>
*/
public static MysqlConnection getConnection() {
- if (App.DEBUG) {
- LOGGER.info("CONNECTION GET", new RuntimeException());
- }
MysqlConnection con;
for (;;) {
con = pool.poll();
@@ -91,9 +88,6 @@ public class Database { * @param connection
*/
static void returnConnection(MysqlConnection connection) {
- if (App.DEBUG) {
- LOGGER.info("CONNECTION RETURN", new RuntimeException());
- }
if (!busyConnections.remove(connection))
throw new RuntimeException("Tried to return a mysql connection to the pool that was not taken!");
pool.add(connection);
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java index 4ca2aef6..fc78a5aa 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java @@ -25,16 +25,6 @@ public class DbImage { private static final Logger LOGGER = Logger.getLogger(DbImage.class); - public static ImageSummaryRead getImageSummary(UserInfo user, String imageBaseId) throws SQLException, - TNotFoundException { - try (MysqlConnection connection = Database.getConnection()) { - return getImageSummary(connection, user, imageBaseId); - } catch (SQLException e) { - LOGGER.error("Query failed in DbImage.getImageSummary()", e); - throw e; - } - } - /** * Get list of all images visible to the given user, optionally filtered by * the given list of tags. @@ -131,7 +121,26 @@ public class DbImage { return entry; } - private static ImageSummaryRead getImageSummary(MysqlConnection connection, UserInfo user, + /** + * Get summary about an image by its base id. + * + * @param user + * @param imageBaseId + * @return + * @throws SQLException + * @throws TNotFoundException + */ + public static ImageSummaryRead getImageSummary(UserInfo user, String imageBaseId) throws SQLException, + TNotFoundException { + try (MysqlConnection connection = Database.getConnection()) { + return getImageSummary(connection, user, imageBaseId); + } catch (SQLException e) { + LOGGER.error("Query failed in DbImage.getImageSummary()", e); + throw e; + } + } + + protected static ImageSummaryRead getImageSummary(MysqlConnection connection, UserInfo user, String imageBaseId) throws SQLException, TNotFoundException { MysqlStatement stmt = connection.prepareStatement("SELECT" + " i.imagebaseid, i.currentversionid, i.latestversionid, i.displayname," @@ -280,7 +289,7 @@ public class DbImage { * @return * @throws SQLException */ - private static String getBaseIdForVersionId(MysqlConnection connection, String imageVersionId) + protected static String getBaseIdForVersionId(MysqlConnection connection, String imageVersionId) throws SQLException { MysqlStatement stmt = connection.prepareStatement("SELECT imagebaseid FROM imageversion" + " WHERE imageversionid = :imageversionid LIMIT 1"); diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java index 18f21498..a40fbbb3 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java @@ -3,6 +3,7 @@ package org.openslx.bwlp.sat.database.mappers; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.UUID; @@ -12,9 +13,10 @@ import org.openslx.bwlp.sat.database.MysqlConnection; import org.openslx.bwlp.sat.database.MysqlStatement; import org.openslx.bwlp.sat.permissions.User; import org.openslx.bwlp.sat.util.Json; -import org.openslx.bwlp.thrift.iface.LecturePermissions; +import org.openslx.bwlp.thrift.iface.LectureRead; import org.openslx.bwlp.thrift.iface.LectureSummary; import org.openslx.bwlp.thrift.iface.LectureWrite; +import org.openslx.bwlp.thrift.iface.NetRule; import org.openslx.bwlp.thrift.iface.TNotFoundException; import org.openslx.bwlp.thrift.iface.UserInfo; @@ -80,7 +82,7 @@ public class DbLecture { MysqlStatement stmt = connection.prepareStatement("UPDATE lecture SET " + " displayname = :displayname, description = :description, imageversionid = :imageversionid," + " autoupdate = :autoupdate, isenabled = :isenabled, starttime = :starttime," - + " endtime = :endtime, createtime = :createtime, updatetime = :updatetime," + + " endtime = :endtime, updatetime = UNIX_TIMESTAMP()," + " updaterid = :updaterid, runscript = :runscript, nics = :nics," + " netrules = :netrules, isexam = :isexam, hasinternetaccess = :hasinternetaccess," + " caneditdefault = :caneditdefault, canadmindefault = :canadmindefault" @@ -111,7 +113,7 @@ public class DbLecture { + " l.lectureid, l.displayname AS lecturename, l.imageversionid, l.isenabled," + " l.starttime, l.endtime, l.lastused, l.usecount, l.ownerid, l.updaterid," + " l.isexam, l.hasinternetaccess, l.caneditdefault, l.canadmindefault," - + " perm.canedit, perm.canadmin" + + " perm.canedit, perm.canadmin FROM lecture l" + " LEFT JOIN lecturepermission perm ON (perm.lectureid = l.lectureid AND perm.userid = :userid)" + " WHERE lectureid = :lectureid"); stmt.setString("lectureid", lectureId); @@ -186,4 +188,73 @@ public class DbLecture { } } + public static LectureRead getLectureDetails(UserInfo user, String lectureId) throws SQLException, + TNotFoundException { + try (MysqlConnection connection = Database.getConnection()) { + MysqlStatement stmt = connection.prepareStatement("SELECT" + + " l.lectureid, l.displayname AS l.lecturename, l.description, l.imageversionid, l.autoupdate," + + " l.isenabled, l.starttime, l.endtime, l.lastused, l.usecount, l.createtime, l.updatetime," + + " l.ownerid, l.updaterid, l.runscript, l.nics, l.netrules, l.isexam, l.hasinternetaccess," + + " l.caneditdefault, l.canadmindefault, p.canedit, p.canadmin" + + " FROM lecture l " + + " LEFT JOIN lecturepermission p ON (l.lectureid = p.lectureid AND p.userid = :userid)" + + " WHERE l.lectureid = :lectureid LIMIT 1"); + stmt.setString("userid", user.userId); + stmt.setString("lectureid", lectureId); + ResultSet rs = stmt.executeQuery(); + if (!rs.next()) + throw new TNotFoundException(); + LectureRead lecture = new LectureRead(); + lecture.setLectureId(rs.getString("lectureid")); + lecture.setLectureName(rs.getString("lecturename")); + lecture.setDescription(rs.getString("description")); + lecture.setAutoUpdate(rs.getBoolean("autoupdate")); + lecture.setIsEnabled(rs.getBoolean("isenabled")); + lecture.setStartTime(rs.getLong("starttime")); + lecture.setEndTime(rs.getLong("endtime")); + lecture.setLastUsed(rs.getLong("lastused")); + lecture.setUseCount(rs.getInt("usecount")); + lecture.setCreateTime(rs.getLong("createtime")); + lecture.setUpdateTime(rs.getLong("updatetime")); + lecture.setOwnerId(rs.getString("ownerid")); + lecture.setUpdaterId(rs.getString("updaterid")); + lecture.setRunscript(rs.getString("runscript")); + lecture.setNetworkExceptions(Arrays.asList(Json.deserializeThrift(rs.getString("netrules"), + NetRule[].class))); + lecture.setImage(DbImage.getImageSummary(connection, user, + DbImage.getBaseIdForVersionId(connection, rs.getString("imageversionid")))); + lecture.setAllowedUsers(getAllowedUsers(connection, lectureId)); + return lecture; + } catch (SQLException e) { + LOGGER.error("Query failed in DbLecture.getLectureDetails()", e); + throw e; + } + } + + public static List<String> getAllowedUsers(MysqlConnection connection, String lectureId) + throws SQLException { + MysqlStatement stmt = connection.prepareStatement("SELECT" + " userlogin FROM lectureuser" + + " WHERE lectureid = :lectureid"); + stmt.setString("lectureid", lectureId); + ResultSet rs = stmt.executeQuery(); + List<String> list = new ArrayList<>(); + while (rs.next()) { + list.add(rs.getString("userlogin")); + } + return list; + } + + public static boolean delete(String lectureId) throws TNotFoundException, SQLException { + int affected; + try (MysqlConnection connection = Database.getConnection()) { + MysqlStatement stmt = connection.prepareStatement("DELETE FROM lecture WHERE lectureid = :lectureid"); + stmt.setString("lectureid", lectureId); + affected = stmt.executeUpdate(); + connection.commit(); + } catch (SQLException e) { + LOGGER.error("Query failed in DbLecture.delete()", e); + throw e; + } + return affected == 1; + } } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/User.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/User.java index 74c9a441..86660ac1 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/User.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/User.java @@ -8,6 +8,8 @@ import org.openslx.bwlp.sat.database.models.LocalOrganization; import org.openslx.bwlp.sat.database.models.LocalUser; import org.openslx.bwlp.sat.permissions.PermCheck.Permission; import org.openslx.bwlp.thrift.iface.AuthorizationError; +import org.openslx.bwlp.thrift.iface.ImageDetailsRead; +import org.openslx.bwlp.thrift.iface.ImageVersionDetails; import org.openslx.bwlp.thrift.iface.Role; import org.openslx.bwlp.thrift.iface.TAuthorizationException; import org.openslx.bwlp.thrift.iface.TInternalServerError; @@ -128,9 +130,26 @@ public class User { */ public static void canDeleteImageVersionOrFail(UserInfo user, String imageVersionId) throws TInternalServerError, TNotFoundException, TAuthorizationException { - // Currently, editing an image also means we can delete it, but let's - // keep this a separate function in case we want to change it some time. - canEditImageVersionOrFail(user, imageVersionId); + ImageDetailsRead imageDetails; + try { + imageDetails = DbImage.getImageDetails(user, DbImage.getBaseIdForVersionId(imageVersionId)); + } catch (SQLException e) { + throw new TInternalServerError(); + } + // User owns the base image - allow + if (imageDetails.ownerId.equals(user.userId)) + return; + // User is image admin - allow + if (PermCheck.canActionImage(user, Permission.ADMIN, imageDetails.userPermissions, + imageDetails.defaultPermissions)) + return; + // User uploaded the image version in question - allow + for (ImageVersionDetails version : imageDetails.versions) { + if (version.uploaderId.equals(user.userId)) + return; + } + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "No permission to delete this image version"); } /** @@ -204,7 +223,21 @@ public class User { public static void canSeeImageDetailsOrFail(UserInfo user) throws TAuthorizationException { if (!isTutor(user)) throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, - "No permission to see list of images"); + "No permission to see image details"); + } + + public static void canSeeLectureDetailsOrFail(UserInfo user) throws TAuthorizationException { + if (!isTutor(user)) + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "No permission to see lecture details"); + } + + public static void canDeleteLectureOrFail(UserInfo user, String lectureId) + throws TAuthorizationException, TInternalServerError, TNotFoundException { + if (!isTutor(user) || !PermCheck.hasLecturePermission(user, lectureId, Permission.ADMIN)) { + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "No permission to delete this lecture"); + } } } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java index 5cf28713..03bb8444 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java @@ -7,6 +7,7 @@ import java.util.Map; import org.apache.log4j.Logger; import org.apache.thrift.TException; +import org.openslx.bwlp.sat.database.Paginator; import org.openslx.bwlp.sat.database.mappers.DbImage; import org.openslx.bwlp.sat.database.mappers.DbImagePermissions; import org.openslx.bwlp.sat.database.mappers.DbLecture; @@ -56,6 +57,11 @@ public class ServerHandler implements SatelliteServer.Iface { return Version.VERSION; } + @Override + public int getPageSize() throws TException { + return Paginator.PER_PAGE; + } + /* * File Transfer */ @@ -324,22 +330,27 @@ public class ServerHandler implements SatelliteServer.Iface { @Override public LectureRead getLectureDetails(String userToken, String lectureId) throws TAuthorizationException, - TNotFoundException { - // TODO Auto-generated method stub - return null; - } - - @Override - public List<LectureSummary> getLecturesByImageVersion(String userToken, String imageVersionId) - throws TAuthorizationException, TNotFoundException { - // TODO Auto-generated method stub - return null; + TNotFoundException, TInternalServerError { + UserInfo user = SessionManager.getOrFail(userToken); + User.canSeeLectureDetailsOrFail(user); + try { + return DbLecture.getLectureDetails(user, lectureId); + } catch (SQLException e) { + throw new TInternalServerError(); + } } @Override public void deleteLecture(String userToken, String lectureId) throws TAuthorizationException, - TNotFoundException { - // TODO Auto-generated method stub + TNotFoundException, TInternalServerError { + UserInfo user = SessionManager.getOrFail(userToken); + User.canDeleteLectureOrFail(user, lectureId); + try { + if (!DbLecture.delete(lectureId)) + throw new TNotFoundException(); + } catch (SQLException e) { + throw new TInternalServerError(); + } } @Override diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/util/Json.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/util/Json.java index fe43793a..bb222792 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/util/Json.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/util/Json.java @@ -1,14 +1,39 @@ package org.openslx.bwlp.sat.util; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; + +import org.apache.log4j.Logger; +import org.apache.thrift.TBase; + import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; public class Json { + private static final Logger LOGGER = Logger.getLogger(Json.class); + /** * Global static instance. The Gson object is thread-safe. */ private static final Gson gson = new Gson(); + private static final GsonBuilder gsonThriftBuilder = new GsonBuilder(); + + public static <T> void registerThriftClass(Class<T> thriftClass) { + if (!TBase.class.isAssignableFrom(thriftClass)) + throw new IllegalArgumentException(thriftClass.getName() + " is not a thrift struct."); + gsonThriftBuilder.registerTypeAdapter(thriftClass, new ThriftDeserializer<T>(thriftClass)); + } + /** * Deserialize the given json string to an instance of T. * This will deserialize all fields, except transient ones. @@ -21,6 +46,10 @@ public class Json { return gson.fromJson(data, classOfData); } + public static <T> T deserializeThrift(String data, Class<T> thriftClass) { + return gsonThriftBuilder.create().fromJson(data, thriftClass); + } + /** * Serialize the given POJO. All fields except transient ones will be * serialized. @@ -32,4 +61,51 @@ public class Json { return gson.toJson(object); } + private static class ThriftDeserializer<T> implements JsonDeserializer<T> { + private final Class<T> clazz; + + public ThriftDeserializer(Class<T> classOfData) { + this.clazz = classOfData; + } + + @Override + public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + if (!(json instanceof JsonObject)) + throw new JsonParseException("Need a json object, have " + json.getClass().getSimpleName()); + JsonObject obj = (JsonObject) json; + final T inst; + try { + inst = clazz.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + LOGGER.warn("Could not deserialize to class " + clazz.getName(), e); + throw new JsonParseException("Cannot instantiate class " + clazz.getSimpleName()); + } + for (Field field : clazz.getFields()) { + if (Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())) + continue; + final String methodName = "set" + field.getName().substring(0, 1).toUpperCase() + + field.getName().substring(1); + final Method setter; + try { + setter = clazz.getMethod(methodName, field.getType()); + } catch (NoSuchMethodException e) { + LOGGER.warn(clazz.getSimpleName() + " has no method " + methodName); + continue; + } + JsonElement element = obj.get(field.getName()); + if (element == null || element.isJsonNull()) + continue; + try { + setter.invoke(inst, context.deserialize(element, field.getType())); + LOGGER.info("Called " + methodName + " on " + clazz.getSimpleName()); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + LOGGER.warn("Could not call " + methodName + " on " + clazz.getSimpleName(), e); + } + } + return inst; + } + + } + } |
