diff --git a/Zallery.iml b/Zallery.iml index b39e141..70b745e 100755 --- a/Zallery.iml +++ b/Zallery.iml @@ -1,5 +1,5 @@ - + @@ -11,12 +11,14 @@ - - + + + + @@ -43,7 +45,6 @@ - @@ -54,5 +55,26 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100755 index 0000000..9942924 --- /dev/null +++ b/pom.xml @@ -0,0 +1,79 @@ + + + + 4.0.0 + + se.koc + zallery + 1.0.0-SNAPSHOT + war + + Zallery + + + + + 1.8 + UTF-8 + + + + + se.koc + zutil + 1.0.0-SNAPSHOT + + + javax.mail + mail + 1.3.2 + + + mysql + mysql-connector-java + 5.1.36 + + + xuggle + xuggle-xuggler + 5.4 + system + ${basedir}/WebContent/WEB-INF/lib/xuggle-xuggler-5.4.jar + + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + + + src + test + + + + maven-compiler-plugin + 3.6.1 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-war-plugin + 3.2.0 + + WebContent + + + + + + + + diff --git a/src/zall/ZalleryConstant.java b/src/zall/ZalleryConstant.java new file mode 100755 index 0000000..620558f --- /dev/null +++ b/src/zall/ZalleryConstant.java @@ -0,0 +1,12 @@ +package zall; + +/** + * Zallery globally defined constants + */ +public interface ZalleryConstant { + + /** Session Constants **/ + + String SESSION_KEY_USER = "zal_user"; + String SESSION_KEY_AUTH_HASH = "zal_session_hash"; +} diff --git a/src/zall/action/RegisterAction.java b/src/zall/action/RegisterAction.java index 20cd986..b95c963 100755 --- a/src/zall/action/RegisterAction.java +++ b/src/zall/action/RegisterAction.java @@ -31,7 +31,7 @@ public class RegisterAction extends ZalleryAction{ msgs.add(MessageType.ERROR, "Please provide a valid email!"); return; } - if( User.emailExists(request.getParameter("email"), db) ){ + if(User.load(db, request.getParameter("email")) != null){ msgs.add(MessageType.ERROR, "An account with that email already exists!"); return; } diff --git a/src/zall/bean/User.java b/src/zall/bean/User.java index 65f199e..c4d6a8d 100755 --- a/src/zall/bean/User.java +++ b/src/zall/bean/User.java @@ -9,13 +9,11 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import zall.Zallery; import zutil.Hasher; import zutil.db.DBConnection; import zutil.db.bean.DBBean; import zutil.db.bean.DBBeanSQLResultHandler; import zutil.db.bean.DBBean.*; -import zutil.db.handler.SimpleSQLResult; @DBTable("User") public class User extends DBBean{ @@ -30,7 +28,6 @@ public class User extends DBBean{ protected String password; // Date protected Timestamp loginDate; - protected transient Timestamp prevLoginDate; // security protected transient AuthType authBy; protected String sessionId; @@ -50,32 +47,21 @@ public class User extends DBBean{ return DBConnection.exec(sql, DBBeanSQLResultHandler.createList(User.class, db)); } - /** * Uses normal user and password to get user object, * this function will save the bean * * @param db is the DB connection * @param email is the email of the user - * @param password is the password of the user - * @param request is the HTTP request object * @return The user object or null if non where found * @throws SQLException */ - public static User load(HttpServletRequest request, HttpServletResponse response, DBConnection db, String email, String password ) throws SQLException{ - if( password==null || password.isEmpty() || password.equalsIgnoreCase("null")) - return null; + public static User load(DBConnection db, String email) throws SQLException{ PreparedStatement sql = db.getPreparedStatement( - "SELECT * FROM User WHERE email=? AND password=? LIMIT 1"); + "SELECT * FROM User WHERE email=? LIMIT 1"); sql.setString(1, email); - sql.setString(2, Hasher.MD5( password )); User user = DBConnection.exec(sql, DBBeanSQLResultHandler.create(User.class, db)); - if( user != null ){ - user.registerOnHost(request, response, db, true ); - user.save(db); - user.setAuthBy( AuthType.USER_INPUT ); - } return user; } @@ -104,7 +90,6 @@ public class User extends DBBean{ if( user != null && user.ipHost.equals( request.getLocalName() ) && user.loginDate.getTime()+SESSION_TIMEOUT > System.currentTimeMillis() ){ - user.prevLoginDate = user.loginDate; user.loginDate = new Timestamp( System.currentTimeMillis() ); user.save(db); user.setAuthBy( AuthType.COOKIE ); @@ -113,14 +98,6 @@ public class User extends DBBean{ return null; } - public static boolean emailExists(String email, DBConnection db) throws SQLException{ - PreparedStatement sql = db.getPreparedStatement( - "SELECT email FROM User WHERE email=? LIMIT 1"); - sql.setString(1, email); - - String tmp = DBConnection.exec(sql, new SimpleSQLResult()); - return tmp != null; - } public User(){ @@ -139,11 +116,10 @@ public class User extends DBBean{ * @throws SQLException */ public void registerOnHost(HttpServletRequest request, HttpServletResponse response, DBConnection db, boolean cookie) throws SQLException{ - prevLoginDate = loginDate; loginDate = new Timestamp( System.currentTimeMillis() ); sessionId = request.getSession().getId(); ipHost = request.getRemoteAddr(); - sessionHash = Hasher.MD5( ""+sessionId+ipHost+loginDate+password ); + sessionHash = generateSessionHash(); if( cookie ){ Cookie c = new Cookie("sessionHash", sessionHash ); c.setMaxAge(5*24*60*60); // 5 days @@ -151,30 +127,11 @@ public class User extends DBBean{ } } - public void logout(HttpServletResponse response) { - Cookie cookie = new Cookie( "sessionHash", null); - cookie.setMaxAge( 0 ); - response.addCookie( cookie ); - } - - public boolean valid(HttpServletRequest request){ - if( !isEnabled() ) return false; - switch( authBy ){ - case USER_INPUT: - if( !isEmailVerified() ) return false; - case COOKIE: - return ( sessionHash.equals( Zallery.getCookieValue(request.getCookies(), "sessionHash")) || - loginDate.getTime()+1000 > System.currentTimeMillis() ) && - ipHost.equals( request.getRemoteAddr() ) && - loginDate.getTime()+SESSION_TIMEOUT > System.currentTimeMillis(); - } - return false; - } public boolean verifyEmail(String hash) { - return emailVerified = getEmailVerificationHash().equals(hash); + return emailVerified = generateEmailVerificationHash().equals(hash); } - public String getEmailVerificationHash(){ + public String generateEmailVerificationHash(){ return Hasher.MD5( "##helloWorld-->2011"+email+name+password ); } @@ -187,20 +144,21 @@ public class User extends DBBean{ public void setLoginDate(Timestamp loginDate) { this.loginDate = loginDate; } - public Timestamp getPrevLoginDate() { - if( loginDate == null ) - loginDate = new Timestamp(0); - return prevLoginDate; + + public void setAuthBy(AuthType authBy){ + this.authBy = authBy; } - public void setPrevLoginDate(Timestamp prevLoginDate) { - this.prevLoginDate = prevLoginDate; + public AuthType getAuthBy(){ + return authBy; } + public String getName() { return name; } public void setName(String name) { this.name = name; } + public String getEmail() { return email; } @@ -210,57 +168,59 @@ public class User extends DBBean{ emailVerified = false; this.email = email; } - public String getPassword() { - return password; - } - public void setPassword(String password) { - this.password = Hasher.MD5( password ); - } - public boolean equalsPassword( String pass ){ - return Hasher.MD5( pass ).equals( password ); - } - public String getSessionId() { - return sessionId; - } - public void setSessionId(String sessionId) { - this.sessionId = sessionId; - } - public String getIpHost() { - return ipHost; - } - public void setIpHost(String ipHost) { - this.ipHost = ipHost; - } - public String getSessionHash() { - return sessionHash; - } - public boolean isSuperUser(){ - return superUser; - } - public void setSuperUser(boolean superuser){ - this.superUser = superuser; - } - public boolean isEnabled(){ - return enabled; - } - public void setEnabled(boolean enabled){ - this.enabled = enabled; - } public boolean isEmailVerified(){ return emailVerified; } public void setEmailVerified(boolean verified){ this.emailVerified = verified; } - public void setAuthBy(AuthType authBy){ - this.authBy = authBy; + + public String getPassword() { + return password; } - public AuthType getAuthBy(){ - return authBy; + public void setPassword(String password) { + this.password = Hasher.MD5( password ); + } + + public String getSessionId() { + return sessionId; + } + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + public String getSessionHash() { + return sessionHash; + } + public void setSessionHash(String sessionHash) { + this.sessionHash = sessionHash; + } + public String generateSessionHash(){ + return Hasher.MD5( ""+sessionId+ipHost+loginDate+password ); + } + + public String getIpHost() { + return ipHost; + } + public void setIpHost(String ipHost) { + this.ipHost = ipHost; + } + + public boolean isSuperUser(){ + return superUser; + } + public void setSuperUser(boolean superUser){ + this.superUser = superUser; + } + + public boolean isEnabled(){ + return enabled; + } + public void setEnabled(boolean enabled){ + this.enabled = enabled; } public boolean equals(User u){ - return u != null && this.getId() == u.getId(); + return u != null && getId() == u.getId(); } } diff --git a/src/zall/filter/AuthenticationFilter.java b/src/zall/filter/AuthenticationFilter.java index 6f9b665..4ccc582 100755 --- a/src/zall/filter/AuthenticationFilter.java +++ b/src/zall/filter/AuthenticationFilter.java @@ -1,6 +1,7 @@ package zall.filter; import zall.bean.User; +import zall.manager.AuthenticationManager; import javax.servlet.*; import javax.servlet.annotation.WebFilter; @@ -18,7 +19,7 @@ public class AuthenticationFilter implements Filter { @Override - public void init(FilterConfig filterConfig) throws ServletException { } + public void init(FilterConfig filterConfig) { } @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { @@ -26,7 +27,7 @@ public class AuthenticationFilter implements Filter { User user = null; // continue the request via the filter pipeline if it is login page or it is a valid User - if (requestURI.equals(LOGIN_URI) || user != null) { + if (requestURI.equals(LOGIN_URI) || AuthenticationManager.valid(user)) { chain.doFilter(request, response); } else { // do not continue the filter pipeline but respond back to client diff --git a/src/zall/manager/AuthenticationManager.java b/src/zall/manager/AuthenticationManager.java index b69b353..1e3b152 100755 --- a/src/zall/manager/AuthenticationManager.java +++ b/src/zall/manager/AuthenticationManager.java @@ -1,13 +1,65 @@ package zall.manager; +import zall.Zallery; +import zall.ZalleryConstant; import zall.bean.Folder; import zall.bean.Media; import zall.bean.User; +import zall.util.msg.UserMessage; +import zutil.Hasher; +import zutil.db.DBConnection; +import zutil.log.LogUtil; + +import javax.servlet.http.HttpServletRequest; +import java.sql.SQLException; +import java.util.logging.Logger; /** * */ public class AuthenticationManager { + private static final Logger logger = LogUtil.getLogger(); + + /** + * Authenticate a username and password and return the associated Uaer object + */ + public static User authenticate(DBConnection db, String email, String password) throws SQLException { + User authenticatedUser = null; + User user = User.load(db, email); + + // Valid email? + if( user != null ){ + if (user.getPassword().equals(Hasher.MD5(password))) { + authenticatedUser = user; + authenticatedUser.setAuthBy(User.AuthType.USER_INPUT); + authenticatedUser.save(db); + logger.info("User(" + authenticatedUser.getName() + ") authenticated by "+authenticatedUser.getAuthBy()); + } + } + return authenticatedUser; + } + + /** + * @return true if the user has a valid authentication session + */ + public static boolean valid(User user, HttpServletRequest request) { + if(user == null) + return false; + if(!user.isEnabled()) + return false; + if(user.getSessionHash() == null || user.getSessionHash().isEmpty() ) + return false; + + switch( user.getAuthBy() ){ + case USER_INPUT: + if (!user.isEmailVerified()) return false; + case COOKIE: + String cookieHash = Zallery.getCookieValue(request.getCookies(), ZalleryConstant.SESSION_KEY_AUTH_HASH); + return user.getSessionHash().equals(cookieHash) && + user.getIpHost().equals( request.getRemoteAddr() ); + } + return false; + } /** * @return true if the specified user can edit the media @@ -27,4 +79,13 @@ public class AuthenticationManager { public static boolean canEdit(User user, User target){ return user.equals( target ) || user.isSuperUser(); } + + + /** + * Reset the user authentication. In plain word: logout user. + */ + public static void reset(DBConnection db, User user) throws SQLException { + user.setSessionHash(null); + user.save(db); + } } diff --git a/src/zall/servlet/LoginServlet.java b/src/zall/servlet/LoginServlet.java index 3508892..8c179cf 100755 --- a/src/zall/servlet/LoginServlet.java +++ b/src/zall/servlet/LoginServlet.java @@ -1,5 +1,10 @@ package zall.servlet; +import zall.bean.User; +import zall.manager.AuthenticationManager; +import zall.util.DbHttpServlet; +import zutil.db.DBConnection; + import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; @@ -7,17 +12,38 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.sql.SQLException; + +import static zall.ZalleryConstant.SESSION_KEY_USER; /** * */ @WebServlet(urlPatterns = "/login") -public class LoginServlet extends HttpServlet { +public class LoginServlet extends DbHttpServlet { private static final String JSP_FILE = "login.jsp"; + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/"+JSP_FILE); - if (dispatcher != null) - dispatcher.include(req, resp); + getServletContext().getRequestDispatcher("/" + JSP_FILE).include(req, resp); + } + + protected void doPost(HttpServletRequest req, HttpServletResponse resp, DBConnection db) throws ServletException, IOException, SQLException { + User user = AuthenticationManager.authenticate(db, + req.getParameter("email"), + req.getParameter("password")); + + + // Successfull login + if (user != null) { + user.registerOnHost(req, resp, db, true ); + req.getSession().setAttribute(SESSION_KEY_USER, user); + + getServletContext().getRequestDispatcher("/").forward(req, resp); + } + // Failed login + else { + getServletContext().getRequestDispatcher("/" + JSP_FILE).include(req, resp); + } } } diff --git a/src/zall/servlet/LogoutServlet.java b/src/zall/servlet/LogoutServlet.java new file mode 100755 index 0000000..3fb93bc --- /dev/null +++ b/src/zall/servlet/LogoutServlet.java @@ -0,0 +1,32 @@ +package zall.servlet; + +import zall.ZalleryConstant; +import zall.bean.User; +import zall.manager.AuthenticationManager; +import zall.util.DbHttpServlet; +import zutil.db.DBConnection; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.sql.SQLException; + +import static zall.ZalleryConstant.SESSION_KEY_USER; + +/** + * + */ +@WebServlet(urlPatterns = "/logout") +public class LogoutServlet extends DbHttpServlet { + + protected void doGet(HttpServletRequest req, HttpServletResponse resp, DBConnection db) throws SQLException, IOException { + User user = (User) req.getSession().getAttribute(SESSION_KEY_USER); + + AuthenticationManager.reset(db, user); + req.getSession().removeAttribute(SESSION_KEY_USER); + + resp.sendRedirect("/login"); + } + +} diff --git a/src/zall/servlet/RegisterServlet.java b/src/zall/servlet/RegisterServlet.java index 86686d4..591c3aa 100755 --- a/src/zall/servlet/RegisterServlet.java +++ b/src/zall/servlet/RegisterServlet.java @@ -16,8 +16,6 @@ public class RegisterServlet extends HttpServlet { private static final String JSP_FILE = "register.jsp"; protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/"+JSP_FILE); - if (dispatcher != null) - dispatcher.include(req, resp); + getServletContext().getRequestDispatcher("/"+JSP_FILE).include(req, resp); } } diff --git a/src/zall/util/DbHttpServlet.java b/src/zall/util/DbHttpServlet.java new file mode 100755 index 0000000..b4740ae --- /dev/null +++ b/src/zall/util/DbHttpServlet.java @@ -0,0 +1,69 @@ +package zall.util; + +import zall.bean.Folder; +import zall.bean.Image; +import zall.bean.Media; +import zall.bean.User; +import zall.manager.AuthenticationManager; +import zall.util.msg.UserMessage; +import zall.util.msg.UserMessage.MessageType; +import zutil.db.DBConnection; +import zutil.log.LogUtil; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.*; +import java.io.File; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +public abstract class DbHttpServlet extends HttpServlet{ + private static Logger logger = LogUtil.getLogger(); + + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + DBConnection db = null; + try{ + doGet(request, response, db = getDB()); + } catch (SQLException e) { + throw new IOException(e); + } finally{ + if(db != null) db.close(); + } + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response, DBConnection db) + throws ServletException, IOException, SQLException { } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + DBConnection db = null; + try{ + doPost(request, response, db = getDB()); + } catch (SQLException e) { + throw new IOException(e); + } finally{ + if(db != null) db.close(); + } + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response, DBConnection db) + throws ServletException, IOException, SQLException { } + + + public static DBConnection getDB() throws ServletException{ + try { + return new DBConnection("jdbc/mysql"); + } catch (Exception e) { + throw new ServletException(e); + } + } +} diff --git a/src/zall/util/ZalleryEmail.java b/src/zall/util/ZalleryEmail.java index 0d771ca..c0e0723 100755 --- a/src/zall/util/ZalleryEmail.java +++ b/src/zall/util/ZalleryEmail.java @@ -28,7 +28,7 @@ public class ZalleryEmail { email.setContentType(Email.ContentType.HTML); email.setMessage("You receive this message because you have requested an account" + "
at "+Zallery.getWebsiteName()+". Please click the link to verify your email address: " + - "

"+Zallery.getWebsiteURL()+"?action=verfemail&id="+user.getId()+"&hash="+user.getEmailVerificationHash()+"" + + "

"+Zallery.getWebsiteURL()+"?action=verfemail&id="+user.getId()+"&hash="+user.generateEmailVerificationHash()+"" + "

You will have to wait for an admin to activate your account after you have verified your email."); SmtpClient smtp = new SmtpClient(host);