mirror of
https://github.com/sismics/docs.git
synced 2025-12-21 05:31:42 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
package com.sismics.util.filter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.PatternLayout;
|
||||
import org.apache.log4j.RollingFileAppender;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.sismics.docs.core.constant.Constants;
|
||||
import com.sismics.docs.core.model.context.AppContext;
|
||||
import com.sismics.docs.core.util.DirectoryUtil;
|
||||
import com.sismics.docs.core.util.TransactionUtil;
|
||||
import com.sismics.util.EnvironmentUtil;
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
import com.sismics.util.jpa.EMF;
|
||||
|
||||
/**
|
||||
* Filter used to process a couple things in the request context.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class RequestContextFilter implements Filter {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(RequestContextFilter.class);
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
// Force the locale in order to not depend on the execution environment
|
||||
Locale.setDefault(new Locale(Constants.DEFAULT_LOCALE_ID));
|
||||
|
||||
// Injects the webapp root
|
||||
String webappRoot = filterConfig.getServletContext().getRealPath("/");
|
||||
EnvironmentUtil.setWebappRoot(webappRoot);
|
||||
|
||||
// Initialize the app directory
|
||||
File baseDataDirectory = null;
|
||||
try {
|
||||
baseDataDirectory = DirectoryUtil.getBaseDataDirectory();
|
||||
} catch (Exception e) {
|
||||
log.error("Error initializing base data directory", e);
|
||||
}
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(MessageFormat.format("Using base data directory: {0}", baseDataDirectory.toString()));
|
||||
}
|
||||
|
||||
// Initialize file logger
|
||||
RollingFileAppender fileAppender = new RollingFileAppender();
|
||||
fileAppender.setName("FILE");
|
||||
fileAppender.setFile(DirectoryUtil.getLogDirectory() + File.separator + "docs.log");
|
||||
fileAppender.setLayout(new PatternLayout("%d{DATE} %p %l %m %n"));
|
||||
fileAppender.setThreshold(Level.INFO);
|
||||
fileAppender.setAppend(true);
|
||||
fileAppender.setMaxFileSize("5MB");
|
||||
fileAppender.setMaxBackupIndex(5);
|
||||
fileAppender.activateOptions();
|
||||
org.apache.log4j.Logger.getRootLogger().addAppender(fileAppender);
|
||||
|
||||
// Initialize the application context
|
||||
TransactionUtil.handle(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
AppContext.getInstance();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// NOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||
EntityManager em = null;
|
||||
|
||||
try {
|
||||
em = EMF.get().createEntityManager();
|
||||
} catch (Exception e) {
|
||||
throw new ServletException("Cannot create entity manager", e);
|
||||
}
|
||||
ThreadLocalContext context = ThreadLocalContext.get();
|
||||
context.setEntityManager(em);
|
||||
EntityTransaction tx = em.getTransaction();
|
||||
tx.begin();
|
||||
|
||||
try {
|
||||
filterChain.doFilter(request, response);
|
||||
} catch (Exception e) {
|
||||
ThreadLocalContext.cleanup();
|
||||
|
||||
log.error("An exception occured, rolling back current transaction", e);
|
||||
|
||||
// If an unprocessed error comes up from the application layers (Jersey...), rollback the transaction (should not happen)
|
||||
if (em.isOpen()) {
|
||||
if (em.getTransaction() != null && em.getTransaction().isActive()) {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
|
||||
try {
|
||||
em.close();
|
||||
} catch (Exception ce) {
|
||||
log.error("Error closing entity manager", ce);
|
||||
}
|
||||
}
|
||||
throw new ServletException(e);
|
||||
}
|
||||
|
||||
ThreadLocalContext.cleanup();
|
||||
|
||||
// No error processing the request : commit / rollback the current transaction depending on the HTTP code
|
||||
if (em.isOpen()) {
|
||||
if (em.getTransaction() != null && em.getTransaction().isActive()) {
|
||||
HttpServletResponse r = (HttpServletResponse) response;
|
||||
int statusClass = r.getStatus() / 100;
|
||||
if (statusClass == 2 || statusClass == 3) {
|
||||
try {
|
||||
em.getTransaction().commit();
|
||||
} catch (Exception e) {
|
||||
log.error("Error during commit", e);
|
||||
r.sendError(500);
|
||||
}
|
||||
} else {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
|
||||
try {
|
||||
em.close();
|
||||
} catch (Exception e) {
|
||||
log.error("Error closing entity manager", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.sismics.util.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.sismics.docs.core.constant.Constants;
|
||||
import com.sismics.docs.core.dao.jpa.AuthenticationTokenDao;
|
||||
import com.sismics.docs.core.dao.jpa.RoleBaseFunctionDao;
|
||||
import com.sismics.docs.core.dao.jpa.UserDao;
|
||||
import com.sismics.docs.core.model.jpa.AuthenticationToken;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
import com.sismics.security.AnonymousPrincipal;
|
||||
import com.sismics.security.UserPrincipal;
|
||||
import com.sismics.util.LocaleUtil;
|
||||
|
||||
/**
|
||||
* This filter is used to authenticate the user having an active session via an authentication token stored in database.
|
||||
* The filter extracts the authentication token stored in a cookie.
|
||||
* If the ocokie exists and the token is valid, the filter injects a UserPrincipal into a request attribute.
|
||||
* If not, the user is anonymous, and the filter injects a AnonymousPrincipal into the request attribute.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class TokenBasedSecurityFilter implements Filter {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(TokenBasedSecurityFilter.class);
|
||||
|
||||
/**
|
||||
* Name of the cookie used to store the authentication token.
|
||||
*/
|
||||
public static final String COOKIE_NAME = "auth_token";
|
||||
|
||||
/**
|
||||
* Name of the attribute containing the principal.
|
||||
*/
|
||||
public static final String PRINCIPAL_ATTRIBUTE = "principal";
|
||||
|
||||
/**
|
||||
* Lifetime of the authentication token in seconds, since login.
|
||||
*/
|
||||
public static final int TOKEN_LONG_LIFETIME = 3600 * 24 * 365 * 20;
|
||||
|
||||
/**
|
||||
* Lifetime of the authentication token in seconds, since last connection.
|
||||
*/
|
||||
public static final int TOKEN_SESSION_LIFETIME = 3600 * 24;
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
// NOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// NOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||
// Get the value of the client authentication token
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
String authToken = null;
|
||||
if (request.getCookies() != null) {
|
||||
for (Cookie cookie : request.getCookies()) {
|
||||
if (COOKIE_NAME.equals(cookie.getName())) {
|
||||
authToken = cookie.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the corresponding server token
|
||||
AuthenticationTokenDao authenticationTokenDao = new AuthenticationTokenDao();
|
||||
AuthenticationToken authenticationToken = null;
|
||||
if (authToken != null) {
|
||||
authenticationToken = authenticationTokenDao.get(authToken);
|
||||
}
|
||||
|
||||
if (authenticationToken == null) {
|
||||
injectAnonymousUser(request);
|
||||
} else {
|
||||
// Check if the token is still valid
|
||||
if (isTokenExpired(authenticationToken)) {
|
||||
try {
|
||||
injectAnonymousUser(request);
|
||||
|
||||
// Destroy the expired token
|
||||
authenticationTokenDao.delete(authToken);
|
||||
} catch (Exception e) {
|
||||
if (log.isErrorEnabled()) {
|
||||
log.error(MessageFormat.format("Error deleting authentication token {0} ", authToken), e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check if the user is still valid
|
||||
UserDao userDao = new UserDao();
|
||||
User user = userDao.getById(authenticationToken.getUserId());
|
||||
if (user != null && user.getDeleteDate() == null) {
|
||||
injectAuthenticatedUser(request, user);
|
||||
|
||||
// Update the last connection date
|
||||
authenticationTokenDao.updateLastConnectionDate(authenticationToken.getId());
|
||||
} else {
|
||||
injectAnonymousUser(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the token is expired.
|
||||
*
|
||||
* @param authenticationToken Authentication token
|
||||
* @return Token expired
|
||||
*/
|
||||
private boolean isTokenExpired(AuthenticationToken authenticationToken) {
|
||||
final long now = new Date().getTime();
|
||||
final long creationDate = authenticationToken.getCreationDate().getTime();
|
||||
if (authenticationToken.isLongLasted()) {
|
||||
return now >= creationDate + ((long) TOKEN_LONG_LIFETIME) * 1000L;
|
||||
} else {
|
||||
long date = authenticationToken.getLastConnectionDate() != null ?
|
||||
authenticationToken.getLastConnectionDate().getTime() : creationDate;
|
||||
return now >= date + ((long) TOKEN_SESSION_LIFETIME) * 1000L;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject an authenticated user into the request attributes.
|
||||
*
|
||||
* @param request HTTP request
|
||||
* @param user User to inject
|
||||
*/
|
||||
private void injectAuthenticatedUser(HttpServletRequest request, User user) {
|
||||
UserPrincipal userPrincipal = new UserPrincipal(user.getId(), user.getUsername());
|
||||
|
||||
// Add locale
|
||||
Locale locale = LocaleUtil.getLocale(user.getLocaleId());
|
||||
userPrincipal.setLocale(locale);
|
||||
|
||||
// Add base functions
|
||||
RoleBaseFunctionDao userBaseFuction = new RoleBaseFunctionDao();
|
||||
Set<String> baseFunctionSet = userBaseFuction.findByRoleId(user.getRoleId());
|
||||
userPrincipal.setBaseFunctionSet(baseFunctionSet);
|
||||
|
||||
request.setAttribute(PRINCIPAL_ATTRIBUTE, userPrincipal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject an anonymous user into the request attributes.
|
||||
*
|
||||
* @param request HTTP request
|
||||
*/
|
||||
private void injectAnonymousUser(HttpServletRequest request) {
|
||||
AnonymousPrincipal anonymousPrincipal = new AnonymousPrincipal();
|
||||
anonymousPrincipal.setLocale(request.getLocale());
|
||||
anonymousPrincipal.setDateTimeZone(DateTimeZone.forID(Constants.DEFAULT_TIMEZONE_ID));
|
||||
|
||||
request.setAttribute(PRINCIPAL_ATTRIBUTE, anonymousPrincipal);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user