diff options
9 files changed, 500 insertions, 237 deletions
diff --git a/dozentenmodulserver/setup/sat-01-schema.sql b/dozentenmodulserver/setup/sat-01-schema.sql index 08a63be8..e07156f8 100644 --- a/dozentenmodulserver/setup/sat-01-schema.sql +++ b/dozentenmodulserver/setup/sat-01-schema.sql @@ -58,7 +58,7 @@ CREATE TABLE IF NOT EXISTS `imagebase` ( `updatetime` bigint(20) NOT NULL, `ownerid` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `updaterid` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, - `sharemode` enum('LOCAL','PUBLISH','DOWNLOAD') NOT NULL, + `sharemode` enum('LOCAL','PUBLISH','DOWNLOAD', 'FROZEN') NOT NULL, `istemplate` tinyint(1) NOT NULL, `canlinkdefault` tinyint(1) NOT NULL, `candownloaddefault` tinyint(1) NOT NULL, 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 aaa344f8..03ae5dd4 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java @@ -67,7 +67,7 @@ public class App { Database.printCharsetInformation(); List<ImageSummaryRead> allVisible; try { - allVisible = DbImage.getAllVisible(new UserInfo("bla", "blu", null, null, null), null); + allVisible = DbImage.getAllVisible(new UserInfo("bla", "blu", null, null, null), null, 0); log.info("Got " + allVisible.size()); } catch (SQLException e) { log.warn("could not test query getallvisible"); 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 1fb19121..4ca2aef6 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 @@ -10,6 +10,7 @@ import org.apache.log4j.Logger; import org.openslx.bwlp.sat.database.Database; import org.openslx.bwlp.sat.database.MysqlConnection; import org.openslx.bwlp.sat.database.MysqlStatement; +import org.openslx.bwlp.sat.database.Paginator; import org.openslx.bwlp.thrift.iface.ImageBaseWrite; import org.openslx.bwlp.thrift.iface.ImageDetailsRead; import org.openslx.bwlp.thrift.iface.ImagePermissions; @@ -42,10 +43,11 @@ public class DbImage { * question * @param tagSearch list of tags an image must have to be included in the * list. + * @param page page to return * @return {@link List} of {@link ImageSummaryRead} * @throws SQLException */ - public static List<ImageSummaryRead> getAllVisible(UserInfo user, List<String> tagSearch) + public static List<ImageSummaryRead> getAllVisible(UserInfo user, List<String> tagSearch, int page) throws SQLException { // TODO: Implement tag search functionality try (MysqlConnection connection = Database.getConnection()) { @@ -60,10 +62,11 @@ public class DbImage { + " FROM imagebase i" + " LEFT JOIN imageversion cur ON (cur.imageversionid = i.currentversionid)" + " LEFT JOIN imageversion lat ON (lat.imageversionid = i.latestversionid)" - + " LEFT JOIN imagepermission perm ON (i.imagebaseid = perm.imagebaseid AND perm.userid = :userid)"); + + " LEFT JOIN imagepermission perm ON (i.imagebaseid = perm.imagebaseid AND perm.userid = :userid)" + + Paginator.limitStatement(page)); stmt.setString("userid", user.userId); ResultSet rs = stmt.executeQuery(); - List<ImageSummaryRead> list = new ArrayList<>(); + List<ImageSummaryRead> list = new ArrayList<>(100); while (rs.next()) { list.add(resultSetToSummary(rs)); } @@ -342,4 +345,18 @@ public class DbImage { } } + public static void setShareMode(String imageBaseId, ImageBaseWrite newData) throws SQLException { + try (MysqlConnection connection = Database.getConnection()) { + MysqlStatement stmt = connection.prepareStatement("UPDATE imagebase" + + " SET sharemode = :sharemode WHERE imagebaseid = :baseid LIMIT 1"); + stmt.setString("baseid", imageBaseId); + stmt.setString("sharemode", newData.shareMode.toString()); + stmt.executeUpdate(); + connection.commit(); + } catch (SQLException e) { + LOGGER.error("Query failed in DbImage.setShareMode()", e); + throw e; + } + } + } 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 7f2fa4c5..18f21498 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 @@ -2,12 +2,15 @@ package org.openslx.bwlp.sat.database.mappers; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import org.apache.log4j.Logger; import org.openslx.bwlp.sat.database.Database; 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.LectureSummary; @@ -116,22 +119,71 @@ public class DbLecture { ResultSet rs = stmt.executeQuery(); if (!rs.next()) throw new TNotFoundException(); - return resultSetToSummary(rs); + LectureSummary lecture = new LectureSummary(); + lecture.setLectureId(rs.getString("lectureid")); + lecture.setLectureName(rs.getString("lecturename")); + lecture.setImageVersionId(rs.getString("imageversionid")); + 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.setOwnerId(rs.getString("ownerid")); + lecture.setUpdaterId(rs.getString("updaterid")); + lecture.setIsExam(rs.getBoolean("isexam")); + lecture.setHasInternetAccess(rs.getBoolean("hasinternetaccess")); + lecture.setDefaultPermissions(DbLecturePermissions.fromResultSetDefault(rs)); + lecture.setUserPermissions(DbLecturePermissions.fromResultSetUser(rs)); + return lecture; } catch (SQLException e) { LOGGER.error("Query failed in DbLecture.getLectureSummary()", e); throw e; } } - private static LectureSummary resultSetToSummary(ResultSet rs) throws SQLException { - LecturePermissions defaultPermissions = DbLecturePermissions.fromResultSetDefault(rs); - LectureSummary entry = new LectureSummary(rs.getString("lectureid"), rs.getString("lecturename"), - rs.getString("imageversionid"), null, rs.getBoolean("isenabled"), rs.getLong("starttime"), - rs.getLong("endtime"), rs.getLong("lastused"), rs.getInt("usecount"), - rs.getString("ownerid"), rs.getString("updaterid"), rs.getBoolean("isexam"), - rs.getBoolean("hasinternetaccess"), defaultPermissions, false); - entry.userPermissions = DbLecturePermissions.fromResultSetUser(rs); - return entry; + public static List<LectureSummary> getAll(UserInfo user, int page) throws SQLException { + try (MysqlConnection connection = Database.getConnection()) { + MysqlStatement stmt = connection.prepareStatement("SELECT" + + " l.lectureid, l.displayname AS lecturename, l.imageversionid, i.imagebaseid," + + " l.isenabled, l.starttime, l.endtime, l.lastused, l.usecount, l.ownerid, l.updaterid," + + " l.isexam, l.hasinternetaccess, l.caneditdefault, l.canadmindefault," + + " i.isenabled AS imgenabled, i.isvalid AS imgvalid, p.canedit, p.canadmin" + + " FROM lecture l " + + " INNER JOIN imageversion i USING (imageversionid)" + + " LEFT JOIN lecturepermission p ON (p.lectureid = l.lectureid AND p.userid = :userid)" + + (User.isStudent(user) ? " WHERE i.isrestricted = 0" : "")); + if (user == null) { + stmt.setString("userid", "-"); + } else { + stmt.setString("userid", user.userId); + } + ResultSet rs = stmt.executeQuery(); + List<LectureSummary> list = new ArrayList<>(100); + while (rs.next()) { + LectureSummary lecture = new LectureSummary(); + lecture.setLectureId(rs.getString("lectureid")); + lecture.setLectureName(rs.getString("lecturename")); + lecture.setImageVersionId(rs.getString("imageversionid")); + lecture.setImageBaseId(rs.getString("imagebaseid")); + 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.setOwnerId(rs.getString("ownerid")); + lecture.setUpdaterId(rs.getString("updaterid")); + lecture.setIsExam(rs.getBoolean("isexam")); + lecture.setHasInternetAccess(rs.getBoolean("hasinternetaccess")); + lecture.setDefaultPermissions(DbLecturePermissions.fromResultSetDefault(rs)); + lecture.setUserPermissions(DbLecturePermissions.fromResultSetUser(rs)); + lecture.setIsImageVersionUsable(rs.getBoolean("imgenabled") && rs.getBoolean("imgvalid")); + list.add(lecture); + } + return list; + } catch (SQLException e) { + LOGGER.error("Query failed in DbLecture.getAll()", e); + throw e; + } } } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/LocalData.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/LocalData.java new file mode 100644 index 00000000..3468d69a --- /dev/null +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/LocalData.java @@ -0,0 +1,65 @@ +package org.openslx.bwlp.sat.permissions; + +import java.sql.SQLException; +import java.util.Map; + +import org.openslx.bwlp.sat.database.mappers.DbOrganization; +import org.openslx.bwlp.sat.database.mappers.DbUser; +import org.openslx.bwlp.sat.database.models.LocalOrganization; +import org.openslx.bwlp.sat.database.models.LocalUser; +import org.openslx.bwlp.thrift.iface.UserInfo; +import org.openslx.util.TimeoutHashMap; + +public class LocalData { + + /** + * Cache local user data, might be called quite often. + */ + private static final Map<String, LocalUser> localUserCache = new TimeoutHashMap<>(60000); + + protected static LocalUser getLocalUser(UserInfo user) { + synchronized (localUserCache) { + LocalUser local = localUserCache.get(user.userId); + if (local != null) + return local; + } + LocalUser localData; + try { + localData = DbUser.getLocalData(user); + } catch (SQLException e) { + return null; + } + if (localData == null) + return null; + synchronized (localUserCache) { + localUserCache.put(user.userId, localData); + } + return localData; + } + + /** + * Cache local organization data, might be called quite often. + */ + private static final Map<String, LocalOrganization> localOrganizationCache = new TimeoutHashMap<>(60000); + + protected static LocalOrganization getLocalOrganization(String organizationId) { + synchronized (localOrganizationCache) { + LocalOrganization local = localOrganizationCache.get(organizationId); + if (local != null) + return local; + } + LocalOrganization localData; + try { + localData = DbOrganization.getLocalData(organizationId); + } catch (SQLException e) { + return null; + } + if (localData == null) + return null; + synchronized (localOrganizationCache) { + localOrganizationCache.put(organizationId, localData); + } + return localData; + } + +} diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/PermCheck.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/PermCheck.java new file mode 100644 index 00000000..6b4af039 --- /dev/null +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/PermCheck.java @@ -0,0 +1,175 @@ +package org.openslx.bwlp.sat.permissions; + +import java.sql.SQLException; + +import org.apache.log4j.Logger; +import org.openslx.bwlp.sat.database.mappers.DbImage; +import org.openslx.bwlp.sat.database.mappers.DbLecture; +import org.openslx.bwlp.thrift.iface.AuthorizationError; +import org.openslx.bwlp.thrift.iface.ImagePermissions; +import org.openslx.bwlp.thrift.iface.ImageSummaryRead; +import org.openslx.bwlp.thrift.iface.LecturePermissions; +import org.openslx.bwlp.thrift.iface.LectureSummary; +import org.openslx.bwlp.thrift.iface.TAuthorizationException; +import org.openslx.bwlp.thrift.iface.TInternalServerError; +import org.openslx.bwlp.thrift.iface.TNotFoundException; +import org.openslx.bwlp.thrift.iface.UserInfo; + +public class PermCheck { + + public static enum Permission { + LINK, + DOWNLOAD, + EDIT, + ADMIN + } + + private static final Logger LOGGER = Logger.getLogger(Permission.class); + + protected static boolean canActionImage(UserInfo user, Permission checkPerm, + ImagePermissions... imagePermissions) { + for (ImagePermissions perm : imagePermissions) { + if (perm == null) + continue; + if (checkPerm == Permission.LINK) + return perm.link; + if (checkPerm == Permission.DOWNLOAD) + return perm.download; + if (checkPerm == Permission.EDIT) + return perm.edit; + if (checkPerm == Permission.ADMIN) + return perm.admin; + } + return false; + } + + protected static boolean canActionLecture(UserInfo user, Permission checkPerm, + LecturePermissions... lecturePermissions) { + if (checkPerm == Permission.DOWNLOAD || checkPerm == Permission.LINK) { + LOGGER.warn("Invalid permission check for lecture: " + checkPerm, new RuntimeException( + "Here's your stack trace")); + return false; + } + for (LecturePermissions perm : lecturePermissions) { + if (perm == null) + continue; + if (checkPerm == Permission.EDIT) + return perm.edit; + if (checkPerm == Permission.ADMIN) + return perm.admin; + } + return false; + } + + /** + * Check if the given user has the given permission for the image identified + * by the given image base id. + * + * @param user + * @param imageBaseId + * @param permission + * @throws TInternalServerError + * @throws TNotFoundException + */ + protected static boolean hasImageBasePermission(UserInfo user, String imageBaseId, Permission permission) + throws TInternalServerError, TNotFoundException { + // Check general permissions + ImageSummaryRead localImage; + try { + localImage = DbImage.getImageSummary(user, imageBaseId); + } catch (SQLException e) { + throw new TInternalServerError(); + } + // Owner has all permissions + if (localImage.ownerId.equals(user.userId)) + return true; + return canActionImage(user, permission, localImage.userPermissions, localImage.defaultPermissions) + || User.isSuperUser(user); + } + + /** + * Check if the given user has the given permission for the image identified + * by the given image base id. + * + * @param user + * @param imageBaseId + * @param permission + * @throws TAuthorizationException + * @throws TInternalServerError + * @throws TNotFoundException + */ + protected static void hasImageBasePermissionOrFail(UserInfo user, String imageBaseId, Permission permission) + throws TAuthorizationException, TInternalServerError, TNotFoundException { + if (!hasImageBasePermission(user, imageBaseId, permission)) { + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, "Required permission: " + + permission.toString()); + } + } + + /** + * Check if the given user has the given permission for the image identified + * by the given image version id. + * + * @param user + * @param imageVersionId + * @param permission + * @throws TInternalServerError + * @throws TNotFoundException + */ + protected static boolean hasImageVersionPermission(UserInfo user, String imageVersionId, + Permission permission) throws TInternalServerError, TNotFoundException { + try { + String imageBaseId = DbImage.getBaseIdForVersionId(imageVersionId); + if (imageBaseId == null) + throw new TNotFoundException(); + return hasImageBasePermission(user, imageBaseId, permission); + } catch (SQLException e) { + throw new TInternalServerError(); + } + } + + /** + * Check if the given user has the given permission for the image identified + * by the given image version id. + * + * @param user + * @param imageVersionId + * @param permission + * @throws TAuthorizationException + * @throws TInternalServerError + * @throws TNotFoundException + */ + protected static void hasImageVersionPermissionOrFail(UserInfo user, String imageVersionId, + Permission permission) throws TAuthorizationException, TInternalServerError, TNotFoundException { + if (!hasImageVersionPermission(user, imageVersionId, permission)) { + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, "Required image permission: " + + permission.toString()); + } + } + + protected static boolean hasLecturePermission(UserInfo user, String lectureId, Permission permission) + throws TInternalServerError, TNotFoundException { + // Check general permissions + LectureSummary lecture; + try { + lecture = DbLecture.getLectureSummary(user, lectureId); + } catch (SQLException e) { + throw new TInternalServerError(); + } + // Owner has all permissions + if (lecture.ownerId.equals(user.userId)) + return true; + return canActionLecture(user, permission, lecture.userPermissions, lecture.defaultPermissions) + || User.isSuperUser(user); + } + + protected static void hasLecturePermissionOrFail(UserInfo user, String lectureId, Permission permission) + throws TAuthorizationException, TInternalServerError, TNotFoundException { + if (!hasLecturePermission(user, lectureId, permission)) { + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "Required lecture permission: " + permission.toString()); + } + } + + +} 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 2ffd281a..74c9a441 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 @@ -1,121 +1,27 @@ package org.openslx.bwlp.sat.permissions; import java.sql.SQLException; -import java.util.Map; -import org.apache.log4j.Logger; import org.openslx.bwlp.sat.database.mappers.DbImage; -import org.openslx.bwlp.sat.database.mappers.DbLecture; import org.openslx.bwlp.sat.database.mappers.DbOrganization; -import org.openslx.bwlp.sat.database.mappers.DbUser; 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.ImagePermissions; -import org.openslx.bwlp.thrift.iface.ImageSummaryRead; -import org.openslx.bwlp.thrift.iface.LecturePermissions; -import org.openslx.bwlp.thrift.iface.LectureSummary; import org.openslx.bwlp.thrift.iface.Role; import org.openslx.bwlp.thrift.iface.TAuthorizationException; import org.openslx.bwlp.thrift.iface.TInternalServerError; import org.openslx.bwlp.thrift.iface.TNotFoundException; import org.openslx.bwlp.thrift.iface.UserInfo; -import org.openslx.util.TimeoutHashMap; public class User { - private static final Logger LOGGER = Logger.getLogger(User.class); - - public static enum Permission { - LINK, - DOWNLOAD, - EDIT, - ADMIN - } - - private static boolean canActionImage(UserInfo user, Permission checkPerm, - ImagePermissions... imagePermissions) { - for (ImagePermissions perm : imagePermissions) { - if (perm == null) - continue; - if (checkPerm == Permission.LINK) - return perm.link; - if (checkPerm == Permission.DOWNLOAD) - return perm.download; - if (checkPerm == Permission.EDIT) - return perm.edit; - if (checkPerm == Permission.ADMIN) - return perm.admin; - } - return false; - } - - private static boolean canActionLecture(UserInfo user, Permission checkPerm, - LecturePermissions... lecturePermissions) { - if (checkPerm == Permission.DOWNLOAD || checkPerm == Permission.LINK) { - LOGGER.warn("Invalid permission check for lecture: " + checkPerm, new RuntimeException( - "Here's your stack trace")); - return false; - } - for (LecturePermissions perm : lecturePermissions) { - if (perm == null) - continue; - if (checkPerm == Permission.EDIT) - return perm.edit; - if (checkPerm == Permission.ADMIN) - return perm.admin; - } - return false; - } - - /** - * Cache local user data, might be called quite often. - */ - private static final Map<String, LocalUser> localUserCache = new TimeoutHashMap<>(60000); - - private static LocalUser getLocalUser(UserInfo user) { - synchronized (localUserCache) { - LocalUser local = localUserCache.get(user.userId); - if (local != null) - return local; - } - LocalUser localData; - try { - localData = DbUser.getLocalData(user); - } catch (SQLException e) { - return null; - } - if (localData == null) - return null; - synchronized (localUserCache) { - localUserCache.put(user.userId, localData); - } - return localData; + public static boolean isTutor(UserInfo user) { + return user.role == Role.TUTOR; } - /** - * Cache local organization data, might be called quite often. - */ - private static final Map<String, LocalOrganization> localOrganizationCache = new TimeoutHashMap<>(60000); - - private static LocalOrganization getLocalOrganization(String organizationId) { - synchronized (localOrganizationCache) { - LocalOrganization local = localOrganizationCache.get(organizationId); - if (local != null) - return local; - } - LocalOrganization localData; - try { - localData = DbOrganization.getLocalData(organizationId); - } catch (SQLException e) { - return null; - } - if (localData == null) - return null; - synchronized (localOrganizationCache) { - localOrganizationCache.put(organizationId, localData); - } - return localData; + public static boolean isStudent(UserInfo user) { + return user.role == Role.STUDENT; } /** @@ -125,7 +31,7 @@ public class User { * @return */ public static boolean isSuperUser(UserInfo user) { - LocalUser localData = getLocalUser(user); + LocalUser localData = LocalData.getLocalUser(user); return localData != null && localData.isSuperUser; } @@ -136,10 +42,10 @@ public class User { * @return true if user is allowed to login to this satellite */ public static boolean canLogin(UserInfo user) { - LocalUser localData = getLocalUser(user); + LocalUser localData = LocalData.getLocalUser(user); if (localData != null) return localData.canLogin; // User locally known, use user-specific permission - LocalOrganization local = getLocalOrganization(user.organizationId); + LocalOrganization local = LocalData.getLocalOrganization(user.organizationId); // User unknown, check per-organization login permission if (local == null) return false; @@ -159,150 +65,146 @@ public class User { } /** - * Check if the given user has the given permission for the image identified - * by the given image base id. + * Checks whether the given user is allowed to create new images. + * Throws {@link TAuthorizationException} if permission is not granted. * - * @param user - * @param imageBaseId - * @param permission - * @throws TInternalServerError - * @throws TNotFoundException + * @param user {@link UserInfo} instance representing the user in question */ - public static boolean hasImageBasePermission(UserInfo user, String imageBaseId, Permission permission) - throws TInternalServerError, TNotFoundException { - // Students can download only, so return false right away if we're not checking for download - if (user.role == Role.STUDENT && permission != Permission.DOWNLOAD) - return false; - // Check general permissions - ImageSummaryRead localImage; - try { - localImage = DbImage.getImageSummary(user, imageBaseId); - } catch (SQLException e) { - throw new TInternalServerError(); - } - // Owner has all permissions - if (localImage.ownerId.equals(user.userId)) - return true; - return canActionImage(user, permission, localImage.userPermissions, localImage.defaultPermissions) - || isSuperUser(user); + public static void canCreateImageOrFail(UserInfo user) throws TAuthorizationException { + if (!isTutor(user)) + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "No permission to create new image"); } /** - * Check if the given user has the given permission for the image identified - * by the given image base id. + * Is given user allowed to edit/update the image identified by the given + * image base id? Throws {@link TAuthorizationException} if permission is + * not granted. * * @param user * @param imageBaseId - * @param permission - * @throws TAuthorizationException - * @throws TInternalServerError * @throws TNotFoundException + * @throws TInternalServerError + * @throws TAuthorizationException */ - public static void hasImageBasePermissionOrFail(UserInfo user, String imageBaseId, Permission permission) - throws TAuthorizationException, TInternalServerError, TNotFoundException { - if (!hasImageBasePermission(user, imageBaseId, permission)) { - throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, "Required permission: " - + permission.toString()); + public static void canEditBaseImageOrFail(UserInfo user, String imageBaseId) throws TInternalServerError, + TNotFoundException, TAuthorizationException { + if (!isTutor(user) || !PermCheck.hasImageBasePermission(user, imageBaseId, Permission.EDIT)) { + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "No permission to edit this image"); } } /** - * Check if the given user has the given permission for the image identified - * by the given image version id. + * Is given user allowed to edit/update the image identified by the given + * image version id? Throws {@link TAuthorizationException} if permission is + * not granted. * * @param user * @param imageVersionId - * @param permission - * @throws TInternalServerError * @throws TNotFoundException + * @throws TInternalServerError + * @throws TAuthorizationException */ - public static boolean hasImageVersionPermission(UserInfo user, String imageVersionId, - Permission permission) throws TInternalServerError, TNotFoundException { + public static void canEditImageVersionOrFail(UserInfo user, String imageVersionId) + throws TInternalServerError, TNotFoundException, TAuthorizationException { try { - String imageBaseId = DbImage.getBaseIdForVersionId(imageVersionId); - if (imageBaseId == null) - throw new TNotFoundException(); - return hasImageBasePermission(user, imageBaseId, permission); + canEditBaseImageOrFail(user, DbImage.getBaseIdForVersionId(imageVersionId)); } catch (SQLException e) { throw new TInternalServerError(); } } /** - * Check if the given user has the given permission for the image identified - * by the given image version id. + * Is given user allowed to delete the image identified by the given + * image version id? Throws {@link TAuthorizationException} if permission is + * not granted. * * @param user * @param imageVersionId - * @param permission * @throws TAuthorizationException - * @throws TInternalServerError * @throws TNotFoundException + * @throws TInternalServerError */ - public static void hasImageVersionPermissionOrFail(UserInfo user, String imageVersionId, - Permission permission) throws TAuthorizationException, TInternalServerError, TNotFoundException { - if (!hasImageVersionPermission(user, imageVersionId, permission)) { - throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, "Required image permission: " - + permission.toString()); - } + 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); } - public static boolean hasLecturePermission(UserInfo user, String lectureId, Permission permission) - throws TInternalServerError, TNotFoundException { - if (user.role != Role.TUTOR) - return false; - // Check general permissions - LectureSummary lecture; - try { - lecture = DbLecture.getLectureSummary(user, lectureId); - } catch (SQLException e) { - throw new TInternalServerError(); - } - // Owner has all permissions - if (lecture.ownerId.equals(user.userId)) - return true; - return canActionLecture(user, permission, lecture.userPermissions, lecture.defaultPermissions) - || isSuperUser(user); + /** + * Checks whether the given user is allowed to create new lectures. + * Throws {@link TAuthorizationException} if permission is not granted. + * + * @param user {@link UserInfo} instance representing the user in question + */ + public static void canCreateLectureOrFail(UserInfo user) throws TAuthorizationException { + if (!isTutor(user)) + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "No permission to create new lecture"); } - public static void hasLecturePermissionOrFail(UserInfo user, String lectureId, Permission permission) - throws TAuthorizationException, TInternalServerError, TNotFoundException { - if (!hasLecturePermission(user, lectureId, permission)) { - throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, - "Required lecture permission: " + permission.toString()); - } + /** + * Checks whether the given user can edit the image identified by the given + * image base id + * + * @param user + * @param imageBaseId + * @return + * @throws TInternalServerError + * @throws TNotFoundException + */ + public static boolean canEditImagePermissions(UserInfo user, String imageBaseId) + throws TInternalServerError, TNotFoundException { + return isTutor(user) && PermCheck.hasImageBasePermission(user, imageBaseId, Permission.ADMIN); } /** - * Checks whether the given user is allowed to create new images. + * Checks whether the given user can edit the image identified by the given + * image base id. + * Throws {@link TAuthorizationException} if permission is not granted. * - * @param user {@link UserInfo} instance representing the user in question - * @return true or false + * @param user + * @param imageBaseId + * @throws TInternalServerError + * @throws TNotFoundException */ - public static boolean canCreateImage(UserInfo user) { - return user.role == Role.TUTOR; + public static void canEditImagePermissionsOrFail(UserInfo user, String imageBaseId) + throws TAuthorizationException, TInternalServerError, TNotFoundException { + if (!canEditImagePermissions(user, imageBaseId)) + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "No permission to edit this image's permissions"); } - public static void canCreateImageOrFail(UserInfo user) throws TAuthorizationException { - if (!canCreateImage(user)) + public static void canChangeImageOwnerOrFail(UserInfo user, String imageBaseId) + throws TAuthorizationException, TInternalServerError, TNotFoundException { + // TODO: Who should be allowed to change the owner? Any admin, or just the owner? + // Currently it's every admin, but this is open for discussion + if (!isTutor(user) || PermCheck.hasImageBasePermission(user, imageBaseId, Permission.ADMIN)) { throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, - "No permission to create new image"); + "No permission to change image owner"); + } } - /** - * Checks whether the given user is allowed to create new lectures. - * - * @param user {@link UserInfo} instance representing the user in question - * @return true or false - */ - public static boolean canCreateLecture(UserInfo user) { - return user.role == Role.TUTOR; + public static void canEditLectureOrFail(UserInfo user, String lectureId) throws TInternalServerError, + TNotFoundException, TAuthorizationException { + if (!isTutor(user) || !PermCheck.hasLecturePermission(user, lectureId, Permission.EDIT)) { + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "No permission to edit this image"); + } } - public static void canCreateLectureOrFail(UserInfo user) throws TAuthorizationException { - if (!canCreateLecture(user)) + public static void canListImagesOrFail(UserInfo user) throws TAuthorizationException { + if (!isTutor(user)) throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, - "No permission to create new lecture"); + "No permission to see list of images"); + } + + public static void canSeeImageDetailsOrFail(UserInfo user) throws TAuthorizationException { + if (!isTutor(user)) + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "No permission to see list of images"); } } 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 cab355a7..5cf28713 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 @@ -14,11 +14,11 @@ import org.openslx.bwlp.sat.database.mappers.DbUser; import org.openslx.bwlp.sat.fileserv.ActiveUpload; import org.openslx.bwlp.sat.fileserv.FileServer; import org.openslx.bwlp.sat.permissions.User; -import org.openslx.bwlp.sat.permissions.User.Permission; import org.openslx.bwlp.sat.thrift.cache.OperatingSystemList; import org.openslx.bwlp.sat.thrift.cache.OrganizationList; import org.openslx.bwlp.sat.thrift.cache.VirtualizerList; import org.openslx.bwlp.sat.util.Util; +import org.openslx.bwlp.thrift.iface.AuthorizationError; import org.openslx.bwlp.thrift.iface.ImageBaseWrite; import org.openslx.bwlp.thrift.iface.ImageDataError; import org.openslx.bwlp.thrift.iface.ImageDetailsRead; @@ -32,6 +32,7 @@ import org.openslx.bwlp.thrift.iface.LectureWrite; import org.openslx.bwlp.thrift.iface.OperatingSystem; import org.openslx.bwlp.thrift.iface.Organization; import org.openslx.bwlp.thrift.iface.SatelliteServer; +import org.openslx.bwlp.thrift.iface.ShareMode; import org.openslx.bwlp.thrift.iface.TAuthorizationException; import org.openslx.bwlp.thrift.iface.TImageDataException; import org.openslx.bwlp.thrift.iface.TInternalServerError; @@ -131,11 +132,12 @@ public class ServerHandler implements SatelliteServer.Iface { */ @Override - public List<ImageSummaryRead> getImageList(String userToken, List<String> tagSearch) + public List<ImageSummaryRead> getImageList(String userToken, List<String> tagSearch, int page) throws TAuthorizationException, TInternalServerError { UserInfo user = SessionManager.getOrFail(userToken); + User.canListImagesOrFail(user); try { - return DbImage.getAllVisible(user, tagSearch); + return DbImage.getAllVisible(user, tagSearch, page); } catch (SQLException e) { throw new TInternalServerError(); } @@ -145,6 +147,7 @@ public class ServerHandler implements SatelliteServer.Iface { public ImageDetailsRead getImageDetails(String userToken, String imageBaseId) throws TAuthorizationException, TNotFoundException, TInternalServerError { UserInfo user = SessionManager.getOrFail(userToken); + User.canSeeImageDetailsOrFail(user); try { return DbImage.getImageDetails(user, imageBaseId); } catch (SQLException e) { @@ -167,17 +170,36 @@ public class ServerHandler implements SatelliteServer.Iface { } @Override - public void updateImageBase(String userToken, String imageBaseId, ImageBaseWrite image) + public void updateImageBase(String userToken, String imageBaseId, ImageBaseWrite newData) throws TAuthorizationException, TInternalServerError, TNotFoundException, TImageDataException { UserInfo user = SessionManager.getOrFail(userToken); - User.hasImageBasePermissionOrFail(user, imageBaseId, Permission.EDIT); - if (!Util.isPrintable(image.imageName) || Util.isEmptyString(image.imageName)) + User.canEditBaseImageOrFail(user, imageBaseId); + // Check image name for invalid characters + if (!Util.isPrintable(newData.imageName) || Util.isEmptyString(newData.imageName)) throw new TImageDataException(ImageDataError.INVALID_DATA, "Invalid or empty name"); - // TODO: Should other fields be validated? Most fields should be protected by fk constraints, - // but the user would only get a generic error, with no hint at the actual problem. + // Check if image is marked for replication. If so, only allow changing the syncmode to FROZEN/DOWNLOAD try { - DbImage.updateImageMetadata(user, imageBaseId, image); - } catch (SQLException e) { + ImageSummaryRead imageSummary = DbImage.getImageSummary(user, imageBaseId); + if (imageSummary.shareMode == ShareMode.DOWNLOAD || imageSummary.shareMode == ShareMode.FROZEN) { + if (newData.shareMode != ShareMode.DOWNLOAD && newData.shareMode != ShareMode.FROZEN) { + throw new TImageDataException(ImageDataError.INVALID_SHARE_MODE, + "Cannot change share mode from remote to local"); + } else { + // Share mode is valid and changed, but ignore all other fields + DbImage.setShareMode(imageBaseId, newData); + return; + } + } else { + // Likewise, if share mode is local or publish, don't allow changing to FROZEN/DOWNLOAD + if (newData.shareMode != ShareMode.LOCAL && newData.shareMode != ShareMode.PUBLISH) { + throw new TImageDataException(ImageDataError.INVALID_SHARE_MODE, + "Cannot change share mode from local to remote"); + } + } + // TODO: Should other fields be validated? Most fields should be protected by fk constraints, + // but the user would only get a generic error, with no hint at the actual problem. + DbImage.updateImageMetadata(user, imageBaseId, newData); + } catch (SQLException e1) { throw new TInternalServerError(); } } @@ -186,10 +208,17 @@ public class ServerHandler implements SatelliteServer.Iface { public void updateImageVersion(String userToken, String imageVersionId, ImageVersionWrite image) throws TAuthorizationException, TInternalServerError, TNotFoundException { UserInfo user = SessionManager.getOrFail(userToken); - User.hasImageVersionPermissionOrFail(user, imageVersionId, Permission.EDIT); + User.canEditImageVersionOrFail(user, imageVersionId); try { + // Do not allow editing remote images + ImageSummaryRead imageSummary = DbImage.getImageSummary(user, + DbImage.getBaseIdForVersionId(imageVersionId)); + if (imageSummary.shareMode == ShareMode.DOWNLOAD || imageSummary.shareMode == ShareMode.FROZEN) { + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "Cannot edit image coming from master server"); + } DbImage.updateImageVersion(user, imageVersionId, image); - } catch (SQLException e) { + } catch (SQLException e1) { throw new TInternalServerError(); } } @@ -198,8 +227,17 @@ public class ServerHandler implements SatelliteServer.Iface { public void deleteImageVersion(String userToken, String imageVersionId) throws TAuthorizationException, TNotFoundException, TInternalServerError { UserInfo user = SessionManager.getOrFail(userToken); - User.hasImageVersionPermissionOrFail(user, imageVersionId, Permission.ADMIN); + User.canDeleteImageVersionOrFail(user, imageVersionId); try { + // Do not allow deleting remote images if share mode is set to "auto download" and + // the version to delete is the latest + ImageSummaryRead imageSummary = DbImage.getImageSummary(user, + DbImage.getBaseIdForVersionId(imageVersionId)); + if (imageSummary.shareMode == ShareMode.DOWNLOAD + && imageSummary.latestVersionId.equals(imageVersionId)) { + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "Cannot delete latest version of image if auto-download is enabled"); + } DbImage.markForDeletion(imageVersionId); } catch (SQLException e) { throw new TInternalServerError(); @@ -211,7 +249,7 @@ public class ServerHandler implements SatelliteServer.Iface { Map<String, ImagePermissions> permissions) throws TAuthorizationException, TNotFoundException, TInternalServerError { UserInfo user = SessionManager.getOrFail(userToken); - User.hasImageBasePermissionOrFail(user, imageBaseId, Permission.ADMIN); + User.canEditImagePermissionsOrFail(user, imageBaseId); try { DbImagePermissions.writeForImageBase(imageBaseId, permissions); } catch (SQLException e) { @@ -223,7 +261,7 @@ public class ServerHandler implements SatelliteServer.Iface { public Map<String, ImagePermissions> getImagePermissions(String userToken, String imageBaseId) throws TAuthorizationException, TNotFoundException, TInternalServerError { UserInfo user = SessionManager.getOrFail(userToken); - boolean adminOnly = !User.hasImageBasePermission(user, imageBaseId, Permission.ADMIN); + boolean adminOnly = !User.canEditImagePermissions(user, imageBaseId); try { return DbImagePermissions.getForImageBase(imageBaseId, adminOnly); } catch (SQLException e) { @@ -235,8 +273,13 @@ public class ServerHandler implements SatelliteServer.Iface { public void setImageOwner(String userToken, String imageBaseId, String newOwnerId) throws TAuthorizationException, TNotFoundException, TInternalServerError, TException { UserInfo user = SessionManager.getOrFail(userToken); - User.hasImageBasePermissionOrFail(user, imageBaseId, Permission.ADMIN); + User.canChangeImageOwnerOrFail(user, imageBaseId); try { + ImageSummaryRead imageSummary = DbImage.getImageSummary(user, imageBaseId); + if (imageSummary.shareMode == ShareMode.DOWNLOAD || imageSummary.shareMode == ShareMode.FROZEN) { + throw new TAuthorizationException(AuthorizationError.NO_PERMISSION, + "Cannot change owner of image that gets downloaded from master server"); + } DbImage.setImageOwner(imageBaseId, newOwnerId); } catch (SQLException e) { throw new TInternalServerError(); @@ -259,7 +302,7 @@ public class ServerHandler implements SatelliteServer.Iface { public void updateLecture(String userToken, String lectureId, LectureWrite lecture) throws TAuthorizationException, TNotFoundException, TInternalServerError { UserInfo user = SessionManager.getOrFail(userToken); - User.hasLecturePermissionOrFail(user, lectureId, Permission.EDIT); + User.canEditLectureOrFail(user, lectureId); try { DbLecture.update(user, lectureId, lecture); } catch (SQLException e) { @@ -268,9 +311,15 @@ public class ServerHandler implements SatelliteServer.Iface { } @Override - public List<LectureSummary> getLectureList(String userToken) throws TAuthorizationException { - // TODO Auto-generated method stub - return null; + public List<LectureSummary> getLectureList(String userToken, int page) throws TAuthorizationException, + TInternalServerError { + UserInfo user = SessionManager.getOrFail(userToken); + try { + // If user is student, getAll() will only return lectures where the current linked image is not restricted + return DbLecture.getAll(user, page); + } catch (SQLException e) { + throw new TInternalServerError(); + } } @Override diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/SessionManager.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/SessionManager.java index 3fdadfb1..ec1c42d3 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/SessionManager.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/SessionManager.java @@ -12,6 +12,7 @@ import org.openslx.bwlp.sat.database.mappers.DbUser; import org.openslx.bwlp.sat.permissions.User; import org.openslx.bwlp.sat.util.QuickTimer; import org.openslx.bwlp.thrift.iface.AuthorizationError; +import org.openslx.bwlp.thrift.iface.Role; import org.openslx.bwlp.thrift.iface.TAuthorizationException; import org.openslx.bwlp.thrift.iface.TInvalidTokenException; import org.openslx.bwlp.thrift.iface.UserInfo; @@ -126,11 +127,13 @@ public class SessionManager { // Valid reply, check if user is allowed to communicate with this satellite server if (!User.canLogin(ui)) return null; - // Is valid, insert/update db record - try { - DbUser.writeUserOnLogin(ui); - } catch (SQLException e) { - return null; + // Is valid, insert/update db record, but ignore students + if (ui.role != Role.STUDENT) { + try { + DbUser.writeUserOnLogin(ui); + } catch (SQLException e) { + return null; + } } tokenManager.put(token, new Entry(ui)); return ui; |