diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/AuthenticationTokenDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/AuthenticationTokenDao.java index 73ce605d..e0cac1b9 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/AuthenticationTokenDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/AuthenticationTokenDao.java @@ -1,6 +1,7 @@ package com.sismics.docs.core.dao.jpa; import java.util.Date; +import java.util.List; import java.util.UUID; import javax.persistence.EntityManager; @@ -96,4 +97,31 @@ public class AuthenticationTokenDao { q.setParameter("id", id); q.executeUpdate(); } + + /** + * Returns all authentication tokens of an user. + * + * @param userId + * @return + */ + @SuppressWarnings("unchecked") + public List getByUserId(String userId) { + EntityManager em = ThreadLocalContext.get().getEntityManager(); + Query q = em.createQuery("select a from AuthenticationToken a where a.userId = :userId"); + q.setParameter("userId", userId); + return q.getResultList(); + } + + /** + * Deletes all authentication tokens of an user. + * + * @param userId + */ + public void deleteByUserId(String userId, String id) { + EntityManager em = ThreadLocalContext.get().getEntityManager(); + Query q = em.createQuery("delete AuthenticationToken a where a.userId = :userId and a.id != :id"); + q.setParameter("userId", userId); + q.setParameter("id", id); + q.executeUpdate(); + } } diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileDao.java index 269bf69c..4287d2c2 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/FileDao.java @@ -91,12 +91,8 @@ public class FileDao { @SuppressWarnings("unchecked") public List getByDocumentId(String documentId) { EntityManager em = ThreadLocalContext.get().getEntityManager(); - - // Get the files Query q = em.createQuery("select f from File f where f.documentId = :documentId and f.deleteDate is null"); q.setParameter("documentId", documentId); - List files = (List) q.getResultList(); - - return files; + return q.getResultList(); } } diff --git a/docs-parent/TODO b/docs-parent/TODO index d299795a..717b181e 100644 --- a/docs-parent/TODO +++ b/docs-parent/TODO @@ -1,4 +1,4 @@ -- List opened sessions and ability to close them (client/server) +- List opened sessions and ability to close them (client) - Display logs (client) - Reordering files and add new files to the end (server) - Tag stats (client/server) diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java index 402b0258..60c44796 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java @@ -417,6 +417,7 @@ public class UserResource extends BaseResource { response.put("status", "ok"); return Response.ok().entity(response).build(); } + /** * Returns the information about the connected user. * @@ -532,4 +533,70 @@ public class UserResource extends BaseResource { return Response.ok().entity(response).build(); } + + /** + * Returns all active sessions. + * + * @return Response + * @throws JSONException + */ + @GET + @Path("session") + @Produces(MediaType.APPLICATION_JSON) + public Response session() throws JSONException { + if (!authenticate()) { + throw new ForbiddenClientException(); + } + + JSONObject response = new JSONObject(); + List sessions = new ArrayList(); + + AuthenticationTokenDao authenticationTokenDao = new AuthenticationTokenDao(); + + for (AuthenticationToken authenticationToken : authenticationTokenDao.getByUserId(principal.getId())) { + JSONObject session = new JSONObject(); + session.put("create_date", authenticationToken.getCreationDate().getTime()); + if (authenticationToken.getLastConnectionDate() != null) { + session.put("last_connection_date", authenticationToken.getLastConnectionDate().getTime()); + } + sessions.add(session); + } + response.put("sessions", sessions); + + return Response.ok().entity(response).build(); + } + + /** + * Deletes all active sessions except the one used for this request. + * + * @return Response + * @throws JSONException + */ + @DELETE + @Path("session") + @Produces(MediaType.APPLICATION_JSON) + public Response deleteSession() throws JSONException { + if (!authenticate()) { + throw new ForbiddenClientException(); + } + + // Get the value of the session token + String authToken = null; + if (request.getCookies() != null) { + for (Cookie cookie : request.getCookies()) { + if (TokenBasedSecurityFilter.COOKIE_NAME.equals(cookie.getName())) { + authToken = cookie.getValue(); + } + } + } + + // Remove other tokens + AuthenticationTokenDao authenticationTokenDao = new AuthenticationTokenDao(); + authenticationTokenDao.deleteByUserId(principal.getId(), authToken); + + // Always return ok + JSONObject response = new JSONObject(); + response.put("status", "ok"); + return Response.ok().entity(response).build(); + } } diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java index 9c55d8c4..42c81f3d 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java @@ -137,9 +137,32 @@ public class TestUserResource extends BaseJerseyTest { Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); String aliceAuthToken = clientUtil.getAuthenticationCookie(response); - // Login user bob + // Login user bob twice String bobAuthToken = clientUtil.login("bob"); + String bobAuthToken2 = clientUtil.login("bob"); + // List sessions + userResource = resource().path("/user/session"); + userResource.addFilter(new CookieAuthenticationFilter(bobAuthToken)); + response = userResource.get(ClientResponse.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + json = response.getEntity(JSONObject.class); + Assert.assertTrue(json.getJSONArray("sessions").length() > 0); + + // Delete all sessions + userResource = resource().path("/user/session"); + userResource.addFilter(new CookieAuthenticationFilter(bobAuthToken)); + response = userResource.delete(ClientResponse.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + + // Check bob user information with token 2 (just deleted) + userResource = resource().path("/user"); + userResource.addFilter(new CookieAuthenticationFilter(bobAuthToken2)); + response = userResource.get(ClientResponse.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + json = response.getEntity(JSONObject.class); + Assert.assertEquals(true, json.getBoolean("anonymous")); + // Check alice user information userResource = resource().path("/user"); userResource.addFilter(new CookieAuthenticationFilter(aliceAuthToken));