mirror of
https://github.com/sismics/docs.git
synced 2024-11-22 05:57:57 +01:00
extensible authentication system
This commit is contained in:
parent
c9606f98d3
commit
99d44f2a92
@ -38,11 +38,14 @@ public class EncryptionUtil {
|
||||
* Generate a private key.
|
||||
*
|
||||
* @return New random private key
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public static String generatePrivateKey() throws NoSuchAlgorithmException {
|
||||
public static String generatePrivateKey() {
|
||||
try {
|
||||
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
|
||||
return new BigInteger(176, random).toString(32);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,6 +50,12 @@ public class RoutingUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email when a route step is validated.
|
||||
*
|
||||
* @param documentId Document ID
|
||||
* @param routeStepDto Route step DTO
|
||||
*/
|
||||
public static void sendRouteStepEmail(String documentId, RouteStepDto routeStepDto) {
|
||||
DocumentDao documentDao = new DocumentDao();
|
||||
Document document = documentDao.getById(documentId);
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.sismics.docs.core.util.authentication;
|
||||
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
|
||||
/**
|
||||
* An authentication handler.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public interface AuthenticationHandler {
|
||||
/**
|
||||
* Authenticate a user.
|
||||
*
|
||||
* @param username Username
|
||||
* @param password Password
|
||||
* @return Authenticated user
|
||||
*/
|
||||
User authenticate(String username, String password);
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.sismics.docs.core.util.authentication;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
import com.sismics.util.ClasspathScanner;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* User utilities.
|
||||
*/
|
||||
public class AuthenticationUtil {
|
||||
/**
|
||||
* List of authentication handlers scanned in the classpath.
|
||||
*/
|
||||
private static final List<AuthenticationHandler> AUTH_HANDLERS = Lists.newArrayList(
|
||||
new ClasspathScanner<AuthenticationHandler>().findClasses(AuthenticationHandler.class, "com.sismics.docs.core.util.authentication")
|
||||
.stream()
|
||||
|
||||
.map(clazz -> {
|
||||
try {
|
||||
return clazz.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}).collect(Collectors.toList()));
|
||||
|
||||
/**
|
||||
* Authenticate a user.
|
||||
*
|
||||
* @param username Username
|
||||
* @param password Password
|
||||
* @return Authenticated user
|
||||
*/
|
||||
public static User authenticate(String username, String password) {
|
||||
for (AuthenticationHandler authenticationHandler : AUTH_HANDLERS) {
|
||||
User user = authenticationHandler.authenticate(username, password);
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.sismics.docs.core.util.authentication;
|
||||
|
||||
import com.sismics.docs.core.dao.jpa.UserDao;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
import com.sismics.util.ClasspathScanner;
|
||||
|
||||
/**
|
||||
* Authenticate using the internal database.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
@ClasspathScanner.Priority(100) // We can add handlers before this one
|
||||
public class InternalAuthenticationHandler implements AuthenticationHandler {
|
||||
@Override
|
||||
public User authenticate(String username, String password) {
|
||||
UserDao userDao = new UserDao();
|
||||
return userDao.authenticate(username, password);
|
||||
}
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
package com.sismics.util;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.reflect.ClassPath;
|
||||
import com.sismics.docs.core.util.format.PdfFormatHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Set;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Classes scanner.
|
||||
@ -23,11 +23,11 @@ public class ClasspathScanner<T> {
|
||||
*
|
||||
* @param topClass Top class or interface
|
||||
* @param pkg In this package
|
||||
* @return Set of classes
|
||||
* @return List of classes
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<Class<T>> findClasses(Class<T> topClass, String pkg) {
|
||||
Set<Class<T>> classes = Sets.newHashSet();
|
||||
public List<Class<T>> findClasses(Class<T> topClass, String pkg) {
|
||||
List<Class<T>> classes = Lists.newArrayList();
|
||||
try {
|
||||
for (ClassPath.ClassInfo classInfo : ClassPath.from(topClass.getClassLoader()).getTopLevelClasses(pkg)) {
|
||||
Class<?> clazz = classInfo.load();
|
||||
@ -38,7 +38,22 @@ public class ClasspathScanner<T> {
|
||||
} catch (Exception e) {
|
||||
log.error("Error loading format handlers", e);
|
||||
}
|
||||
|
||||
classes.sort((o1, o2) -> {
|
||||
Priority priority1 = o1.getDeclaredAnnotation(Priority.class);
|
||||
Priority priority2 = o2.getDeclaredAnnotation(Priority.class);
|
||||
return Integer.compare(priority1 == null ? Integer.MAX_VALUE : priority1.value(),
|
||||
priority2 == null ? Integer.MAX_VALUE : priority2.value());
|
||||
});
|
||||
|
||||
log.info("Found " + classes.size() + " classes for " + topClass.getSimpleName());
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Classpath scanning priority.
|
||||
*/
|
||||
public @interface Priority {
|
||||
int value() default Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.sismics.docs.core.dao.jpa;
|
||||
import com.sismics.docs.BaseTransactionalTest;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
import com.sismics.docs.core.util.TransactionUtil;
|
||||
import com.sismics.docs.core.util.authentication.InternalAuthenticationHandler;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -18,6 +19,7 @@ public class TestJpa extends BaseTransactionalTest {
|
||||
UserDao userDao = new UserDao();
|
||||
User user = new User();
|
||||
user.setUsername("username");
|
||||
user.setPassword("12345678");
|
||||
user.setEmail("toto@docs.com");
|
||||
user.setRoleId("admin");
|
||||
user.setStorageCurrent(0l);
|
||||
@ -31,5 +33,8 @@ public class TestJpa extends BaseTransactionalTest {
|
||||
user = userDao.getById(id);
|
||||
Assert.assertNotNull(user);
|
||||
Assert.assertEquals("toto@docs.com", user.getEmail());
|
||||
|
||||
// Authenticate using the database
|
||||
Assert.assertNotNull(new InternalAuthenticationHandler().authenticate("username", "12345678"));
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
package com.sismics.docs.core.util;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherInputStream;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Test of the encryption utilities.
|
||||
@ -18,7 +16,7 @@ import com.google.common.io.ByteStreams;
|
||||
*/
|
||||
public class TestEncryptUtil {
|
||||
@Test
|
||||
public void generatePrivateKeyTest() throws Exception {
|
||||
public void generatePrivateKeyTest() {
|
||||
String key = EncryptionUtil.generatePrivateKey();
|
||||
System.out.println(key);
|
||||
Assert.assertFalse(Strings.isNullOrEmpty(key));
|
||||
|
@ -5,7 +5,6 @@ import com.sismics.docs.core.dao.jpa.UserDao;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
@ -26,7 +25,7 @@ public class HeaderBasedSecurityFilter extends SecurityFilter {
|
||||
private boolean enabled;
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
public void init(FilterConfig filterConfig) {
|
||||
enabled = Boolean.parseBoolean(filterConfig.getInitParameter("enabled"))
|
||||
|| Boolean.parseBoolean(System.getProperty("docs.header_authentication"));
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import com.sismics.docs.core.model.context.AppContext;
|
||||
import com.sismics.docs.core.model.jpa.*;
|
||||
import com.sismics.docs.core.util.ConfigUtil;
|
||||
import com.sismics.docs.core.util.EncryptionUtil;
|
||||
import com.sismics.docs.core.util.authentication.AuthenticationUtil;
|
||||
import com.sismics.docs.core.util.jpa.SortCriteria;
|
||||
import com.sismics.docs.rest.constant.BaseFunction;
|
||||
import com.sismics.rest.exception.ClientException;
|
||||
@ -38,7 +39,6 @@ import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.NewCookie;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -101,11 +101,7 @@ public class UserResource extends BaseResource {
|
||||
user.setEmail(email);
|
||||
user.setStorageQuota(storageQuota);
|
||||
user.setStorageCurrent(0L);
|
||||
try {
|
||||
user.setPrivateKey(EncryptionUtil.generatePrivateKey());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new ServerException("PrivateKeyError", "Error while generating a private key", e);
|
||||
}
|
||||
user.setCreateDate(new Date());
|
||||
|
||||
// Create the user
|
||||
@ -339,7 +335,7 @@ public class UserResource extends BaseResource {
|
||||
}
|
||||
} else {
|
||||
// Login as a normal user
|
||||
user = userDao.authenticate(username, password);
|
||||
user = AuthenticationUtil.authenticate(username, password);
|
||||
}
|
||||
if (user == null) {
|
||||
throw new ForbiddenClientException();
|
||||
|
Loading…
Reference in New Issue
Block a user