#85: Login as guest

This commit is contained in:
jendib 2016-05-29 16:37:26 +02:00
parent ead01ce1d0
commit d7865cfaf0
No known key found for this signature in database
GPG Key ID: 06EE7F699579166F
7 changed files with 125 additions and 38 deletions

View File

@ -30,6 +30,11 @@ public class Constants {
*/
public static final String LUCENE_DIRECTORY_STORAGE_FILE = "FILE";
/**
* Guest user ID.
*/
public static final String GUEST_USER_ID = "guest";
/**
* Default generic user role.
*/

View File

@ -1,2 +1,3 @@
insert into T_CONFIG(CFG_ID_C, CFG_VALUE_C) values('GUEST_LOGIN', 'false');
insert into T_USER(USE_ID_C, USE_IDROLE_C, USE_USERNAME_C, USE_PASSWORD_C, USE_EMAIL_C, USE_CREATEDATE_D, USE_PRIVATEKEY_C) values('guest', 'user', 'guest', '', 'guest@localhost', NOW(), 'GuestPk');
update T_CONFIG set CFG_VALUE_C = '10' where CFG_ID_C = 'DB_VERSION';

View File

@ -59,4 +59,9 @@ public class AnonymousPrincipal implements IPrincipal {
public Set<String> getGroupIdSet() {
return Sets.newHashSet();
}
@Override
public boolean isGuest() {
return false;
}
}

View File

@ -18,6 +18,13 @@ public interface IPrincipal extends Principal {
*/
boolean isAnonymous();
/**
* Checks if the principal is a guest.
*
* @return True if the principal is a guest
*/
boolean isGuest();
/**
* Returns the ID of the connected user, or null if the user is anonymous
*

View File

@ -2,6 +2,7 @@ package com.sismics.security;
import java.util.Set;
import com.sismics.docs.core.constant.Constants;
import org.joda.time.DateTimeZone;
/**
@ -108,4 +109,9 @@ public class UserPrincipal implements IPrincipal {
public void setGroupIdSet(Set<String> groupIdSet) {
this.groupIdSet = groupIdSet;
}
@Override
public boolean isGuest() {
return Constants.GUEST_USER_ID.equals(id);
}
}

View File

@ -22,6 +22,8 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import com.sismics.docs.core.constant.ConfigType;
import com.sismics.docs.core.util.ConfigUtil;
import org.apache.commons.lang.StringUtils;
import com.google.common.base.Strings;
@ -150,7 +152,7 @@ public class UserResource extends BaseResource {
* @apiParam {String{8..50}} password Password
* @apiParam {String{1..100}} email E-mail
* @apiSuccess {String} status Status OK
* @apiError (client) ForbiddenError Access denied
* @apiError (client) ForbiddenError Access denied or connected as guest
* @apiError (client) ValidationError Validation error
* @apiPermission user
* @apiVersion 1.5.0
@ -163,7 +165,7 @@ public class UserResource extends BaseResource {
public Response update(
@FormParam("password") String password,
@FormParam("email") String email) {
if (!authenticate()) {
if (!authenticate() || principal.isGuest()) {
throw new ForbiddenClientException();
}
@ -301,7 +303,7 @@ public class UserResource extends BaseResource {
* @apiName PostUserLogin
* @apiGroup User
* @apiParam {String} username Username
* @apiParam {String} password Password
* @apiParam {String} password Password (optional for guest login)
* @apiParam {String} code TOTP validation code
* @apiParam {Boolean} remember If true, create a long lasted token
* @apiSuccess {String} auth_token A cookie named auth_token containing the token ID
@ -328,7 +330,16 @@ public class UserResource extends BaseResource {
// Get the user
UserDao userDao = new UserDao();
User user = userDao.authenticate(username, password);
User user = null;
if (username.equals(Constants.GUEST_USER_ID)) {
if (ConfigUtil.getConfigBooleanValue(ConfigType.GUEST_LOGIN)) {
// Login as guest
user = userDao.getActiveByUsername(Constants.GUEST_USER_ID);
}
} else {
// Login as a normal user
user = userDao.authenticate(username, password);
}
if (user == null) {
throw new ForbiddenClientException();
}
@ -429,7 +440,7 @@ public class UserResource extends BaseResource {
* @apiName DeleteUser
* @apiGroup User
* @apiSuccess {String} status Status OK
* @apiError (client) ForbiddenError Access denied or the admin user cannot be deleted
* @apiError (client) ForbiddenError Access denied or the user cannot be deleted
* @apiPermission user
* @apiVersion 1.5.0
*
@ -442,8 +453,8 @@ public class UserResource extends BaseResource {
}
// Ensure that the admin user is not deleted
if (hasBaseFunction(BaseFunction.ADMIN)) {
throw new ClientException("ForbiddenError", "The admin user cannot be deleted");
if (hasBaseFunction(BaseFunction.ADMIN) || principal.isGuest()) {
throw new ClientException("ForbiddenError", "This user cannot be deleted");
}
// Find linked data
@ -486,7 +497,7 @@ public class UserResource extends BaseResource {
* @apiName DeleteUserUsername
* @apiGroup User
* @apiSuccess {String} status Status OK
* @apiError (client) ForbiddenError Access denied or the admin user cannot be deleted
* @apiError (client) ForbiddenError Access denied or the user cannot be deleted
* @apiError (client) UserNotFound The user does not exist
* @apiPermission admin
* @apiVersion 1.5.0
@ -502,6 +513,11 @@ public class UserResource extends BaseResource {
}
checkBaseFunction(BaseFunction.ADMIN);
// Cannot delete the guest user
if (Constants.GUEST_USER_ID.equals(username)) {
throw new ClientException("ForbiddenError", "The guest user cannot be deleted");
}
// Check if the user exists
UserDao userDao = new UserDao();
User user = userDao.getActiveByUsername(username);
@ -768,18 +784,21 @@ public class UserResource extends BaseResource {
String authToken = getAuthToken();
JsonArrayBuilder sessions = Json.createArrayBuilder();
AuthenticationTokenDao authenticationTokenDao = new AuthenticationTokenDao();
for (AuthenticationToken authenticationToken : authenticationTokenDao.getByUserId(principal.getId())) {
JsonObjectBuilder session = Json.createObjectBuilder()
.add("create_date", authenticationToken.getCreationDate().getTime())
.add("ip", JsonUtil.nullable(authenticationToken.getIp()))
.add("user_agent", JsonUtil.nullable(authenticationToken.getUserAgent()));
if (authenticationToken.getLastConnectionDate() != null) {
session.add("last_connection_date", authenticationToken.getLastConnectionDate().getTime());
// The guest user cannot see other sessions
if (!principal.isGuest()) {
AuthenticationTokenDao authenticationTokenDao = new AuthenticationTokenDao();
for (AuthenticationToken authenticationToken : authenticationTokenDao.getByUserId(principal.getId())) {
JsonObjectBuilder session = Json.createObjectBuilder()
.add("create_date", authenticationToken.getCreationDate().getTime())
.add("ip", JsonUtil.nullable(authenticationToken.getIp()))
.add("user_agent", JsonUtil.nullable(authenticationToken.getUserAgent()));
if (authenticationToken.getLastConnectionDate() != null) {
session.add("last_connection_date", authenticationToken.getLastConnectionDate().getTime());
}
session.add("current", authenticationToken.getId().equals(authToken));
sessions.add(session);
}
session.add("current", authenticationToken.getId().equals(authToken));
sessions.add(session);
}
JsonObjectBuilder response = Json.createObjectBuilder()
@ -795,7 +814,7 @@ public class UserResource extends BaseResource {
* @apiName DeleteUserSession
* @apiGroup User
* @apiSuccess {String} status Status OK
* @apiError (client) ForbiddenError Access denied
* @apiError (client) ForbiddenError Access denied or connected as guest
* @apiPermission user
* @apiVersion 1.5.0
*
@ -804,7 +823,7 @@ public class UserResource extends BaseResource {
@DELETE
@Path("session")
public Response deleteSession() {
if (!authenticate()) {
if (!authenticate() || principal.isGuest()) {
throw new ForbiddenClientException();
}
@ -830,7 +849,7 @@ public class UserResource extends BaseResource {
* @apiName PostUserEnableTotp
* @apiGroup User
* @apiSuccess {String} secret Secret TOTP seed to initiate the algorithm
* @apiError (client) ForbiddenError Access denied
* @apiError (client) ForbiddenError Access denied or connected as guest
* @apiPermission user
* @apiVersion 1.5.0
*
@ -839,7 +858,7 @@ public class UserResource extends BaseResource {
@POST
@Path("enable_totp")
public Response enableTotp() {
if (!authenticate()) {
if (!authenticate() || principal.isGuest()) {
throw new ForbiddenClientException();
}
@ -866,7 +885,7 @@ public class UserResource extends BaseResource {
* @apiGroup User
* @apiParam {String{1..100}} password Password
* @apiSuccess {String} status Status OK
* @apiError (client) ForbiddenError Access denied
* @apiError (client) ForbiddenError Access denied or connected as guest
* @apiError (client) ValidationError Validation error
* @apiPermission user
* @apiVersion 1.5.0
@ -877,7 +896,7 @@ public class UserResource extends BaseResource {
@POST
@Path("disable_totp")
public Response disableTotp(@FormParam("password") String password) {
if (!authenticate()) {
if (!authenticate() || principal.isGuest()) {
throw new ForbiddenClientException();
}

View File

@ -1,5 +1,13 @@
package com.sismics.docs.rest;
import com.sismics.docs.core.constant.PermType;
import com.sismics.docs.core.dao.jpa.AclDao;
import com.sismics.util.context.ThreadLocalContext;
import com.sismics.util.filter.TokenBasedSecurityFilter;
import com.sismics.util.jpa.EMF;
import org.junit.Assert;
import org.junit.Test;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.persistence.EntityManager;
@ -9,15 +17,6 @@ import javax.ws.rs.core.Form;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import com.sismics.docs.core.constant.PermType;
import com.sismics.docs.core.dao.jpa.AclDao;
import com.sismics.util.context.ThreadLocalContext;
import com.sismics.util.jpa.EMF;
import org.junit.Assert;
import org.junit.Test;
import com.sismics.util.filter.TokenBasedSecurityFilter;
/**
* Test the app resource.
@ -134,9 +133,10 @@ public class TestAppResource extends BaseJerseyTest {
// Login admin
String adminToken = clientUtil.login("admin", "admin", false);
// Try to login without credentials
// Try to login as guest
Response response = target().path("/user/login").request()
.post(Entity.form(new Form()));
.post(Entity.form(new Form()
.param("username", "guest")));
Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
// Enable guest login
@ -144,5 +144,49 @@ public class TestAppResource extends BaseJerseyTest {
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
.post(Entity.form(new Form()
.param("enabled", "true")), JsonObject.class);
// Login as guest
String guestToken = clientUtil.login("guest", "", false);
// Guest cannot delete himself
response = target().path("/user").request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, guestToken)
.delete();
Assert.assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
// Guest cannot see opened sessions
JsonObject json = target().path("/user/session").request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, guestToken)
.get(JsonObject.class);
Assert.assertEquals(0, json.getJsonArray("sessions").size());
// Guest cannot delete opened sessions
response = target().path("/user/session").request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, guestToken)
.delete();
Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
// Guest cannot enable TOTP
response = target().path("/user/enable_totp").request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, guestToken)
.post(Entity.form(new Form()));
Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
// Guest cannot disable TOTP
response = target().path("/user/disable_totp").request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, guestToken)
.post(Entity.form(new Form()));
Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
// Guest cannot update itself
response = target().path("/user").request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, guestToken)
.post(Entity.form(new Form()));
Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
// Guest can see its documents
target().path("/document/list").request()
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, guestToken)
.get(JsonObject.class);
}
}