mirror of
https://github.com/sismics/docs.git
synced 2024-11-22 05:57:57 +01:00
#85: Login as guest
This commit is contained in:
parent
ead01ce1d0
commit
d7865cfaf0
@ -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.
|
||||
*/
|
||||
|
@ -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';
|
||||
|
@ -59,4 +59,9 @@ public class AnonymousPrincipal implements IPrincipal {
|
||||
public Set<String> getGroupIdSet() {
|
||||
return Sets.newHashSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGuest() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user