diff --git a/pom.xml b/pom.xml index ea1f9b240cfd8e9b142360c96de77970f32996a1..992ab71416e139e6ff66e78e641dbebe89662514 100644 --- a/pom.xml +++ b/pom.xml @@ -257,6 +257,26 @@ <artifactId>jackson-databind</artifactId> <version>2.1.0</version> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-aop</artifactId> + <version>${org.springframework-version}</version> + </dependency> + <dependency> + <groupId>org.aspectj</groupId> + <artifactId>aspectjrt</artifactId> + <version>1.7.1</version> + </dependency> + <dependency> + <groupId>aspectj</groupId> + <artifactId>aspectjweaver</artifactId> + <version>1.5.4</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-aspects</artifactId> + <version>${org.springframework-version}</version> + </dependency> </dependencies> <build> <plugins> diff --git a/src/main/java/de/thm/arsnova/annotation/Authenticated.java b/src/main/java/de/thm/arsnova/annotation/Authenticated.java new file mode 100644 index 0000000000000000000000000000000000000000..b619ea11da21cec10bd94a08af1be3b76d4f2930 --- /dev/null +++ b/src/main/java/de/thm/arsnova/annotation/Authenticated.java @@ -0,0 +1,12 @@ +package de.thm.arsnova.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Authenticated { + +} diff --git a/src/main/java/de/thm/arsnova/aop/AuthorizationAdviser.java b/src/main/java/de/thm/arsnova/aop/AuthorizationAdviser.java new file mode 100644 index 0000000000000000000000000000000000000000..6e7ee94c7985806cc77518900f232d99a2066cd3 --- /dev/null +++ b/src/main/java/de/thm/arsnova/aop/AuthorizationAdviser.java @@ -0,0 +1,41 @@ +package de.thm.arsnova.aop; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.security.core.context.SecurityContextHolder; + +import de.thm.arsnova.annotation.Authenticated; +import de.thm.arsnova.entities.User; +import de.thm.arsnova.exceptions.UnauthorizedException; +import de.thm.arsnova.services.IUserService; + +@Aspect +public class AuthorizationAdviser { + + static IUserService userService; + + public void setUserService(IUserService uService) { + userService = uService; + } + + /** This method checks if the user has a valid authorization from security context + * + * @param authenticated + * @param object + */ + @Before("execution(public * de.thm.arsnova.services.*.*(..)) && @annotation(authenticated) && this(object)") + public void checkAuthorization(Authenticated authenticated, Object object) { + User u = userService.getUser(SecurityContextHolder.getContext().getAuthentication()); + if (u == null) throw new UnauthorizedException(); + } + + /** This method checks if the user is enlisted in current ARSnova session + * + * @param authenticated + * @param object + */ + @Before("execution(public * de.thm.arsnova.services.*.*(..)) && @annotation(authenticated) && this(object)") + public void checkSessionMembership(Authenticated authenticated, Object object) { + //TODO: Implement check based on session membership lists + } +} diff --git a/src/main/java/de/thm/arsnova/controller/AbstractController.java b/src/main/java/de/thm/arsnova/controller/AbstractController.java new file mode 100644 index 0000000000000000000000000000000000000000..251dafbea2c19f66deb39fc9e63b86f184ac7571 --- /dev/null +++ b/src/main/java/de/thm/arsnova/controller/AbstractController.java @@ -0,0 +1,31 @@ +package de.thm.arsnova.controller; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; + +import de.thm.arsnova.exceptions.ForbiddenException; +import de.thm.arsnova.exceptions.NotFoundException; +import de.thm.arsnova.exceptions.UnauthorizedException; + +public class AbstractController { + @ResponseStatus(HttpStatus.NOT_FOUND) + @ExceptionHandler(NotFoundException.class) + public void handleNotFoundException(Exception e, HttpServletRequest request) { + + } + + @ResponseStatus(HttpStatus.FORBIDDEN) + @ExceptionHandler(ForbiddenException.class) + public void handleForbiddenException(Exception e, HttpServletRequest request) { + + } + + @ResponseStatus(HttpStatus.UNAUTHORIZED) + @ExceptionHandler(UnauthorizedException.class) + public void handleUnauthorizedException(Exception e, HttpServletRequest request) { + + } +} diff --git a/src/main/java/de/thm/arsnova/LoginController.java b/src/main/java/de/thm/arsnova/controller/LoginController.java similarity index 98% rename from src/main/java/de/thm/arsnova/LoginController.java rename to src/main/java/de/thm/arsnova/controller/LoginController.java index 5f1ae033e6231bad25b763f39c292aae96ddc776..083bdcf47dbabfbbf5b2b2f4171a15a756dc6635 100644 --- a/src/main/java/de/thm/arsnova/LoginController.java +++ b/src/main/java/de/thm/arsnova/controller/LoginController.java @@ -16,7 +16,7 @@ * 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 de.thm.arsnova; +package de.thm.arsnova.controller; import java.io.IOException; import java.util.ArrayList; @@ -47,7 +47,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.View; import org.springframework.web.servlet.view.RedirectView; @@ -55,7 +54,7 @@ import de.thm.arsnova.entities.User; import de.thm.arsnova.services.IUserService; @Controller -public class LoginController { +public class LoginController extends AbstractController { @Autowired TwitterProvider twitterProvider; diff --git a/src/main/java/de/thm/arsnova/controller/SessionController.java b/src/main/java/de/thm/arsnova/controller/SessionController.java new file mode 100644 index 0000000000000000000000000000000000000000..c268a084561061fd45c67cbd01a1b4fb1ed87320 --- /dev/null +++ b/src/main/java/de/thm/arsnova/controller/SessionController.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2012 THM webMedia + * + * This file is part of ARSnova. + * + * ARSnova 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, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova 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 de.thm.arsnova.controller; + +import java.util.UUID; + +import javax.servlet.http.HttpServletResponse; + +import net.sf.json.JSONObject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import de.thm.arsnova.entities.Feedback; +import de.thm.arsnova.entities.Session; +import de.thm.arsnova.entities.User; +import de.thm.arsnova.services.ISessionService; +import de.thm.arsnova.services.IUserService; +import de.thm.arsnova.socket.ARSnovaSocketIOServer; +import de.thm.arsnova.socket.message.Question; + +@Controller +public class SessionController extends AbstractController { + + public static final Logger logger = LoggerFactory.getLogger(SessionController.class); + + @Autowired + ISessionService sessionService; + + @Autowired + IUserService userService; + + @Autowired + ARSnovaSocketIOServer server; + + @RequestMapping(method = RequestMethod.POST, value = "/authorize") + public void authorize(@RequestBody Object sessionObject, HttpServletResponse response) { + String sessionkey = (String) JSONObject.fromObject(sessionObject).get("session"); + if(sessionkey == null) { + return; + } + User u = userService.getUser(SecurityContextHolder.getContext().getAuthentication()); + logger.info("authorize session: " + sessionkey + ", user is: " + u); + response.setStatus(u != null ? HttpStatus.CREATED.value() : HttpStatus.UNAUTHORIZED.value()); + server.authorize(UUID.fromString(sessionkey), u); + } + + @RequestMapping(value="/session/{sessionkey}", method=RequestMethod.GET) + @ResponseBody + public Session getSession(@PathVariable String sessionkey) { + return sessionService.getSession(sessionkey); + } + + @RequestMapping(value="/session/{sessionkey}/feedback", method=RequestMethod.GET) + @ResponseBody + public Feedback getFeedback(@PathVariable String sessionkey) { + return sessionService.getFeedback(sessionkey); + } + + @RequestMapping(value="/session/{sessionkey}/feedback", method=RequestMethod.POST) + @ResponseBody + public Feedback postFeedback(@PathVariable String sessionkey, @RequestBody int value, HttpServletResponse response) { + User user = userService.getUser(SecurityContextHolder.getContext().getAuthentication()); + if (sessionService.saveFeedback(sessionkey, value, user)) { + Feedback feedback = sessionService.getFeedback(sessionkey); + if (feedback != null) { + // TODO: Broadcast feedback changes via websocket + response.setStatus(HttpStatus.CREATED.value()); + return feedback; + } + + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + return null; + } + + response.setStatus(HttpStatus.BAD_REQUEST.value()); + return null; + } + + @RequestMapping(value="/session", method=RequestMethod.POST) + @ResponseBody + public Session postNewSession(@RequestBody Session session, HttpServletResponse response) { + Session newSession = sessionService.saveSession(session); + if (session != null) { + response.setStatus(HttpStatus.CREATED.value()); + return newSession; + } + + response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value()); + return null; + } + + @RequestMapping(value="/session/{sessionkey}/question/{questionId}", method=RequestMethod.GET) + @ResponseBody + public Question getQuestion(@PathVariable String sessionkey, @PathVariable String questionId, HttpServletResponse response) { + Question question = sessionService.getQuestion(questionId); + if (question != null && question.getSession().equals(sessionkey)) { + return question; + } + + response.setStatus(HttpStatus.NOT_FOUND.value()); + return null; + } + + @RequestMapping(value="/session/{sessionkey}/question", method=RequestMethod.POST) + @ResponseBody + public void postQuestion(@PathVariable String sessionkey, @RequestBody Question question, HttpServletResponse response) { + if (! sessionkey.equals(question.getSession())) { + response.setStatus(HttpStatus.PRECONDITION_FAILED.value()); + return; + } + + if (sessionService.saveQuestion(question)) { + response.setStatus(HttpStatus.CREATED.value()); + return; + } + + response.setStatus(HttpStatus.BAD_REQUEST.value()); + return; + } + + @RequestMapping(value="/socketurl", method=RequestMethod.GET) + @ResponseBody + public String getSocketUrl() { + StringBuilder url = new StringBuilder(); + + url.append(server.isUseSSL() ? "https://" : "http://"); + url.append(server.getHostIp() + ":" + server.getPortNumber()); + + return url.toString(); + } +} diff --git a/src/main/java/de/thm/arsnova/WelcomeController.java b/src/main/java/de/thm/arsnova/controller/WelcomeController.java similarity index 93% rename from src/main/java/de/thm/arsnova/WelcomeController.java rename to src/main/java/de/thm/arsnova/controller/WelcomeController.java index ab9a692673bcc555dfb887aa8f6d23abe0ed89a6..5f900cf96724c7055271ad616f46bda7bc6083ab 100644 --- a/src/main/java/de/thm/arsnova/WelcomeController.java +++ b/src/main/java/de/thm/arsnova/controller/WelcomeController.java @@ -16,7 +16,7 @@ * 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 de.thm.arsnova; +package de.thm.arsnova.controller; import javax.servlet.http.HttpServletRequest; @@ -26,7 +26,7 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; @Controller -public class WelcomeController { +public class WelcomeController extends AbstractController { @RequestMapping(method = RequestMethod.GET, value = "/") public ModelAndView home(HttpServletRequest request) { String referer = request.getHeader("referer"); diff --git a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java index 75d41c1c4089eba7a5777161ba384c2ecf7101fa..dc79f08af12fe1e8856b93569f0f07f2db1b7648 100644 --- a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java +++ b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java @@ -58,6 +58,8 @@ import com.fourspaces.couchdb.ViewResults; import de.thm.arsnova.entities.Feedback; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; +import de.thm.arsnova.exceptions.ForbiddenException; +import de.thm.arsnova.exceptions.NotFoundException; import de.thm.arsnova.services.ISessionService; import de.thm.arsnova.services.IUserService; import de.thm.arsnova.socket.message.PossibleAnswer; @@ -156,14 +158,14 @@ public class CouchDBDao implements IDatabaseDao { public Session getSession(String keyword) { Session result = this.getSessionFromKeyword(keyword); if(result == null) { - return null; + throw new NotFoundException(); } if (result.isActive() || result.getCreator().equals(this.actualUserName())) { sessionService.addUserToSessionMap(this.actualUserName(), keyword); return result; } - return null; + throw new ForbiddenException(); } @Override @@ -281,8 +283,7 @@ public class CouchDBDao implements IDatabaseDao { @Override public Feedback getFeedback(String keyword) { String sessionId = this.getSessionId(keyword); - if (sessionId == null) - return null; + if (sessionId == null) throw new NotFoundException(); logger.info("Time: {}", this.currentTimestamp()); @@ -291,11 +292,10 @@ public class CouchDBDao implements IDatabaseDao { view.setStartKey(URLEncoder.encode("[\"" + sessionId + "\"]")); view.setEndKey(URLEncoder.encode("[\"" + sessionId + "\",{}]")); ViewResults results = this.getDatabase().view(view); - + logger.info("Feedback: {}", results.getJSONArray("rows")); int values[] = { 0, 0, 0, 0 }; - List<Integer> result = new ArrayList<Integer>(); try { for (int i = 0; i <= 3; i++) { @@ -315,12 +315,7 @@ public class CouchDBDao implements IDatabaseDao { .getInt("value"); } } catch (Exception e) { - return new Feedback( - values[0], - values[1], - values[2], - values[3] - ); + throw new NotFoundException(); } return new Feedback( @@ -489,4 +484,26 @@ public class CouchDBDao implements IDatabaseDao { } return false; } + + + @Override + public Question getQuestion(String id) { + try { + View view = new View("skill_question/by_id"); + view.setKey(URLEncoder.encode("\"" + id + "\"", "UTF-8")); + ViewResults results = this.getDatabase().view(view); + + if (results.getJSONArray("rows").optJSONObject(0) == null) { + return null; + } + + return (Question) JSONObject.toBean( + results.getJSONArray("rows").optJSONObject(0).optJSONObject("value"), + Question.class + ); + } catch (IOException e) { + logger.error("Could not get question with id {}", id); + } + return null; + } } diff --git a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java index 27fc1f582d43816a65a5c5add800e84cbeef8088..1b433a0eca55dde74674cdca0a1f6424ebf63003 100644 --- a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java +++ b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java @@ -37,6 +37,7 @@ public interface IDatabaseDao { public boolean sessionKeyAvailable(String keyword); public boolean saveQuestion(Session session, Question question); + public Question getQuestion(String id); List<Question> getSkillQuestions(String session, String sort); public int getSkillQuestionCount(String sessionkey); } \ No newline at end of file diff --git a/src/main/java/de/thm/arsnova/exceptions/ForbiddenException.java b/src/main/java/de/thm/arsnova/exceptions/ForbiddenException.java new file mode 100644 index 0000000000000000000000000000000000000000..8f1f74d51b90f97c572c9a72d7043a5ea50c4638 --- /dev/null +++ b/src/main/java/de/thm/arsnova/exceptions/ForbiddenException.java @@ -0,0 +1,5 @@ +package de.thm.arsnova.exceptions; + +public class ForbiddenException extends RuntimeException { + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/de/thm/arsnova/exceptions/NotFoundException.java b/src/main/java/de/thm/arsnova/exceptions/NotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..caca267d47096bb3d1e3777ff14959f400e5e2e4 --- /dev/null +++ b/src/main/java/de/thm/arsnova/exceptions/NotFoundException.java @@ -0,0 +1,5 @@ +package de.thm.arsnova.exceptions; + +public class NotFoundException extends RuntimeException { + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/de/thm/arsnova/exceptions/UnauthorizedException.java b/src/main/java/de/thm/arsnova/exceptions/UnauthorizedException.java new file mode 100644 index 0000000000000000000000000000000000000000..4b3e9498408dcf6476029d127e23184e6e33584e --- /dev/null +++ b/src/main/java/de/thm/arsnova/exceptions/UnauthorizedException.java @@ -0,0 +1,5 @@ +package de.thm.arsnova.exceptions; + +public class UnauthorizedException extends RuntimeException { + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/de/thm/arsnova/services/ISessionService.java b/src/main/java/de/thm/arsnova/services/ISessionService.java index 73de3b58a860a7e01a2b459b9e8e44939eef5bd3..67ab4eeb4eeb9821684261e5bfff690cbe8c9852 100644 --- a/src/main/java/de/thm/arsnova/services/ISessionService.java +++ b/src/main/java/de/thm/arsnova/services/ISessionService.java @@ -26,6 +26,7 @@ import java.util.Set; import de.thm.arsnova.entities.Feedback; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; + import de.thm.arsnova.socket.message.Question; @@ -45,6 +46,7 @@ public interface ISessionService { public List<Session> getMySessions(String username); public boolean saveQuestion(Question question); + public Question getQuestion(String id); public List<Question> getSkillQuestions(String sessionkey, String sort); public int getSkillQuestionCount(String sessionkey); } \ No newline at end of file diff --git a/src/main/java/de/thm/arsnova/services/SessionService.java b/src/main/java/de/thm/arsnova/services/SessionService.java index 72189c5c7cc5ab8f4f4ef435907ab3662f95be89..55b77fceb0e92d1629c487f2bc864c164c8d9f13 100644 --- a/src/main/java/de/thm/arsnova/services/SessionService.java +++ b/src/main/java/de/thm/arsnova/services/SessionService.java @@ -33,6 +33,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; +import de.thm.arsnova.annotation.Authenticated; import de.thm.arsnova.dao.IDatabaseDao; import de.thm.arsnova.entities.Feedback; import de.thm.arsnova.entities.Session; @@ -68,9 +69,11 @@ public class SessionService implements ISessionService { } @Override + @Authenticated public Session getSession(String keyword) { return databaseDao.getSession(keyword); } + @Override public List<Session> getMySessions(String username) { return databaseDao.getMySessions(username); @@ -87,16 +90,19 @@ public class SessionService implements ISessionService { } @Override + @Authenticated public Session saveSession(Session session) { return databaseDao.saveSession(session); } @Override + @Authenticated public Feedback getFeedback(String keyword) { return databaseDao.getFeedback(keyword); } @Override + @Authenticated public boolean saveFeedback(String keyword, int value, User user) { return databaseDao.saveFeedback(keyword, value, user); } @@ -158,8 +164,15 @@ public class SessionService implements ISessionService { } @Override + @Authenticated public boolean saveQuestion(Question question) { Session session = this.databaseDao.getSessionFromKeyword(question.getSession()); return this.databaseDao.saveQuestion(session, question); } + + @Override + @Authenticated + public Question getQuestion(String id) { + return databaseDao.getQuestion(id); + } } diff --git a/src/main/webapp/WEB-INF/arsnova-servlet.xml b/src/main/webapp/WEB-INF/arsnova-servlet.xml index 065ede7792c55e5eda6ce96cd5a496b46dee550f..6a17391e4530b1636f89da579fb88ed015a7a6a9 100644 --- a/src/main/webapp/WEB-INF/arsnova-servlet.xml +++ b/src/main/webapp/WEB-INF/arsnova-servlet.xml @@ -4,4 +4,5 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <!-- ARSnova Root Context: defines shared resources visible to all OTHER web components --> + </beans> diff --git a/src/main/webapp/WEB-INF/spring/spring-main.xml b/src/main/webapp/WEB-INF/spring/spring-main.xml index 65feca0d96e4e6a4ce8c67aed81da92c4ff1715a..6e54457940dc46869fcce7935e542478d77deb67 100644 --- a/src/main/webapp/WEB-INF/spring/spring-main.xml +++ b/src/main/webapp/WEB-INF/spring/spring-main.xml @@ -1,13 +1,18 @@ <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" - xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" - xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task" - xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:p="http://www.springframework.org/schema/p" + xmlns:util="http://www.springframework.org/schema/util" + xmlns:mvc="http://www.springframework.org/schema/mvc" + xmlns:task="http://www.springframework.org/schema/task" + xmlns:aop="http://www.springframework.org/schema/aop" + xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd + http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd + http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd - http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd"> + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" @@ -23,6 +28,8 @@ <import resource="spring-security.xml" /> <context:component-scan base-package="de.thm.arsnova" /> + <context:annotation-config /> + <mvc:annotation-driven /> <mvc:resources mapping="/**" location="/" /> diff --git a/src/test/java/de/thm/arsnova/controller/LoginControllerTest.java b/src/test/java/de/thm/arsnova/controller/LoginControllerTest.java index 03741d10e75b58c08368210a93a922496b7facf6..ea2c531d163c2fdd8d6d419cee2fbeecda76c61b 100644 --- a/src/test/java/de/thm/arsnova/controller/LoginControllerTest.java +++ b/src/test/java/de/thm/arsnova/controller/LoginControllerTest.java @@ -40,7 +40,8 @@ import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; import org.springframework.web.servlet.view.RedirectView; -import de.thm.arsnova.LoginController; +import de.thm.arsnova.services.StubUserService; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={ @@ -59,6 +60,9 @@ public class LoginControllerTest { @Autowired private LoginController loginController; + @Autowired + private StubUserService userService; + @Before public void setUp() throws Exception { this.request = new MockHttpServletRequest(); @@ -102,12 +106,14 @@ public class LoginControllerTest { @Test public void testUser() throws Exception { + userService.setUserAuthenticated(true); + request.setMethod("GET"); request.setRequestURI("/whoami"); handlerAdapter.handle(request, response, loginController); assertNotNull(response); - assertEquals(response.getContentAsString(),"{\"username\":\"Guest1234567890\"}"); + assertEquals(response.getContentAsString(),"{\"username\":\"ptsr00\"}"); } @Test diff --git a/src/test/java/de/thm/arsnova/controller/SessionControllerTest.java b/src/test/java/de/thm/arsnova/controller/SessionControllerTest.java index 74804a308a04d7f568212f18d5a472283bc26ed8..ca68421241ddd0051484d19f8b78c5a564ef5732 100644 --- a/src/test/java/de/thm/arsnova/controller/SessionControllerTest.java +++ b/src/test/java/de/thm/arsnova/controller/SessionControllerTest.java @@ -1,6 +1,7 @@ package de.thm.arsnova.controller; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import javax.inject.Inject; @@ -18,14 +19,16 @@ import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; -import de.thm.arsnova.SessionController; +import de.thm.arsnova.exceptions.ForbiddenException; +import de.thm.arsnova.exceptions.NotFoundException; +import de.thm.arsnova.exceptions.UnauthorizedException; +import de.thm.arsnova.services.StubUserService; @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations={ +@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/arsnova-servlet.xml", "file:src/main/webapp/WEB-INF/spring/spring-main.xml", - "file:src/test/resources/test-config.xml" -}) + "file:src/test/resources/test-config.xml" }) public class SessionControllerTest { @Inject @@ -33,28 +36,171 @@ public class SessionControllerTest { private MockHttpServletRequest request; private MockHttpServletResponse response; private HandlerAdapter handlerAdapter; - + @Autowired private SessionController sessionController; + @Autowired + private StubUserService userService; + @Before public void setUp() { this.request = new MockHttpServletRequest(); this.response = new MockHttpServletResponse(); - handlerAdapter = applicationContext.getBean(AnnotationMethodHandlerAdapter.class); + handlerAdapter = applicationContext + .getBean(AnnotationMethodHandlerAdapter.class); + } + + @Test + public void testShouldNotGetUnknownSession() { + userService.setUserAuthenticated(true); + + request.setMethod("GET"); + request.setRequestURI("/session/00000000"); + try { + final ModelAndView mav = handlerAdapter.handle(request, response, + sessionController); + assertNull(mav); + assertTrue(response.getStatus() == 404); + } catch (NotFoundException e) { + return; + } catch (Exception e) { + e.printStackTrace(); + fail("An exception occured"); + } + + fail("Expected exception 'NotFoundException' did not occure"); + } + + @Test + public void testShouldNotGetForbiddenSession() { + userService.setUserAuthenticated(true); + + request.setMethod("GET"); + request.setRequestURI("/session/99999999"); + try { + final ModelAndView mav = handlerAdapter.handle(request, response, + sessionController); + assertNull(mav); + assertTrue(response.getStatus() == 403); + } catch (ForbiddenException e) { + return; + } catch (Exception e) { + e.printStackTrace(); + fail("An exception occured"); + } + + fail("Expected exception 'ForbiddenException' did not occure"); } @Test - public void testShouldNotGetMissingSession() { + public void testShouldNotGetSessionIfUnauthorized() { + userService.setUserAuthenticated(false); + request.setMethod("GET"); - request.setRequestURI("/session/12345678"); + request.setRequestURI("/session/00000000"); try { - final ModelAndView mav = handlerAdapter.handle(request, response, sessionController); + final ModelAndView mav = handlerAdapter.handle(request, response, + sessionController); assertNull(mav); + assertTrue(response.getStatus() == 401); + } catch (UnauthorizedException e) { + return; } catch (Exception e) { e.printStackTrace(); fail("An exception occured"); } + + fail("Expected exception 'UnauthorizedException' did not occure"); + } + + @Test + public void testShouldCreateSessionIfUnauthorized() { + userService.setUserAuthenticated(false); + request.setMethod("POST"); + request.setRequestURI("/session"); + request.setContentType("application/json"); + request.setContent("{}".getBytes()); + + try { + final ModelAndView mav = handlerAdapter.handle(request, response, + sessionController); + assertNull(mav); + assertTrue(response.getStatus() == 401); + } catch (UnauthorizedException e) { + return; + } catch (Exception e) { + e.printStackTrace(); + fail("An exception occured"); + } + + fail("Expected exception 'UnauthorizedException' did not occure"); + } + + @Test + public void testShouldNotGetFeedbackForUnknownSession() { + userService.setUserAuthenticated(true); + + request.setMethod("GET"); + request.setRequestURI("/session/00000000/feedback"); + try { + final ModelAndView mav = handlerAdapter.handle(request, response, + sessionController); + assertNull(mav); + assertTrue(response.getStatus() == 404); + } catch (NotFoundException e) { + return; + } catch (Exception e) { + e.printStackTrace(); + fail("An exception occured"); + } + + fail("Expected exception 'NotFoundException' did not occure"); + } + + @Test + public void testShouldNotGetFeedbackIfUnauthorized() { + userService.setUserAuthenticated(false); + + request.setMethod("GET"); + request.setRequestURI("/session/00000000/feedback"); + try { + final ModelAndView mav = handlerAdapter.handle(request, response, + sessionController); + assertNull(mav); + assertTrue(response.getStatus() == 401); + } catch (UnauthorizedException e) { + return; + } catch (Exception e) { + e.printStackTrace(); + fail("An exception occured"); + } + + fail("Expected exception 'UnauthorizedException' did not occure"); + } + + @Test + public void testShouldNotSaveFeedbackIfUnauthorized() { + userService.setUserAuthenticated(false); + + request.setMethod("POST"); + request.setRequestURI("/session/00000000/feedback"); + request.setContentType("application/json"); + request.setContent("0".getBytes()); + + try { + final ModelAndView mav = handlerAdapter.handle(request, response, + sessionController); + assertNull(mav); + assertTrue(response.getStatus() == 401); + } catch (UnauthorizedException e) { + return; + } catch (Exception e) { + e.printStackTrace(); + fail("An exception occured"); + } + + fail("Expected exception 'UnauthorizedException' did not occure"); } } diff --git a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java index c8cffa378634f81b5e52c12da0ce8aa0ac671784..4de50c0e540778e8fb00d205794d4509d4cf52ef 100644 --- a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java +++ b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java @@ -4,12 +4,16 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import de.thm.arsnova.entities.Feedback; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; +import de.thm.arsnova.exceptions.ForbiddenException; +import de.thm.arsnova.exceptions.NotFoundException; import de.thm.arsnova.socket.message.Question; @Component @@ -20,6 +24,8 @@ public class StubDatabaseDao implements IDatabaseDao { private Map<String, Feedback> stubFeedbacks = new ConcurrentHashMap<String, Feedback>(); private Map<Session, Question> stubQuestions = new ConcurrentHashMap<Session, Question>(); + private final Logger logger = LoggerFactory.getLogger(getClass()); + public StubDatabaseDao() { fillWithDummySessions(); fillWithDummyFeedbacks(); @@ -56,7 +62,13 @@ public class StubDatabaseDao implements IDatabaseDao { @Override public Session getSession(String keyword) { - return stubSessions.get(keyword); + // Magic keyword for forbidden session + if (keyword.equals("99999999")) throw new ForbiddenException(); + + Session session = stubSessions.get(keyword); + if (session == null) throw new NotFoundException(); + + return session; } @Override @@ -67,7 +79,13 @@ public class StubDatabaseDao implements IDatabaseDao { @Override public Feedback getFeedback(String keyword) { - return stubFeedbacks.get(keyword); + // Magic keyword for forbidden session + if (keyword.equals("99999999")) throw new ForbiddenException(); + + Feedback feedback = stubFeedbacks.get(keyword); + if (feedback == null) throw new NotFoundException(); + + return feedback; } @Override @@ -109,8 +127,8 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<Session> getMySessions(String username) { - // TODO Auto-generated method stub + public Question getQuestion(String id) { + // Simply ... no such question ;-) return null; } diff --git a/src/test/java/de/thm/arsnova/services/SessionServiceTest.java b/src/test/java/de/thm/arsnova/services/SessionServiceTest.java index d2b0b41a882e5f5c333df0bc64db7314ff4b4294..3b950f226ff6c1fdf32c6b81976a0752005a43cd 100644 --- a/src/test/java/de/thm/arsnova/services/SessionServiceTest.java +++ b/src/test/java/de/thm/arsnova/services/SessionServiceTest.java @@ -27,6 +27,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import de.thm.arsnova.exceptions.NotFoundException; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={ "file:src/main/webapp/WEB-INF/arsnova-servlet.xml", @@ -37,10 +39,20 @@ public class SessionServiceTest { @Autowired ISessionService sessionService; + + @Autowired + StubUserService userService; @Test public void testShouldFail() { - if (sessionService.getFeedback("00000000") != null) fail("Result is not null"); + try { + userService.setUserAuthenticated(true); + sessionService.getFeedback("00000000"); + } catch (NotFoundException e) { + return; + } + + fail("Expected exception 'NotFoundException' did not occure"); } @Test diff --git a/src/test/java/de/thm/arsnova/services/StubUserService.java b/src/test/java/de/thm/arsnova/services/StubUserService.java new file mode 100644 index 0000000000000000000000000000000000000000..8ab9f5712167ce10d7d1580a68e9a9aa9e8c437a --- /dev/null +++ b/src/test/java/de/thm/arsnova/services/StubUserService.java @@ -0,0 +1,25 @@ +package de.thm.arsnova.services; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; + +import de.thm.arsnova.entities.User; +import de.thm.arsnova.services.IUserService; + +public class StubUserService implements IUserService { + + private User stubUser = null; + + public void setUserAuthenticated(boolean isAuthenticated) { + if (isAuthenticated) { + stubUser = new User(new UsernamePasswordAuthenticationToken("ptsr00","testpassword")); + return; + } + stubUser = null; + } + + @Override + public User getUser(Authentication authentication) { + return stubUser; + } +} diff --git a/src/test/resources/test-config.xml b/src/test/resources/test-config.xml index db94937d9b63d296ec9c3b8423b22c1903e5e80e..1ef56bd0a43f9a898f7e34f04d76917a90d3d11f 100644 --- a/src/test/resources/test-config.xml +++ b/src/test/resources/test-config.xml @@ -6,10 +6,15 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <bean id="sessionService" class="de.thm.arsnova.services.SessionService"> - <property name="databaseDao" ref="databaseDao"></property> + <property name="databaseDao" ref="databaseDao" /> </bean> <bean id="databaseDao" class="de.thm.arsnova.dao.StubDatabaseDao"> </bean> + <bean id="authorizationAdviser" class="de.thm.arsnova.aop.AuthorizationAdviser"> + <property name="userService" ref="userService" /> + </bean> + + <bean id="userService" class="de.thm.arsnova.services.StubUserService" /> </beans>