Author: taylor Date: Mon May 6 00:29:49 2019 New Revision: 1858717 URL: http://svn.apache.org/viewvc?rev=1858717&view=rev Log: JS2-1368: RememberMe Login Filter, contribution from Giacomo Morri
Added: portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/security/impl/RememberMePortalFilter.java Added: portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/security/impl/RememberMePortalFilter.java URL: http://svn.apache.org/viewvc/portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/security/impl/RememberMePortalFilter.java?rev=1858717&view=auto ============================================================================== --- portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/security/impl/RememberMePortalFilter.java (added) +++ portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/main/java/org/apache/jetspeed/security/impl/RememberMePortalFilter.java Mon May 6 00:29:49 2019 @@ -0,0 +1,413 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jetspeed.security.impl; + +import org.apache.commons.lang.time.DateUtils; +import org.apache.jetspeed.Jetspeed; +import org.apache.jetspeed.PortalReservedParameters; +import org.apache.jetspeed.administration.PortalAuthenticationConfiguration; +import org.apache.jetspeed.administration.PortalConfiguration; +import org.apache.jetspeed.audit.AuditActivity; +import org.apache.jetspeed.cache.UserContentCacheManager; +import org.apache.jetspeed.components.ComponentManager; +import org.apache.jetspeed.container.session.PortalSessionValidationFilter; +import org.apache.jetspeed.login.LoginConstants; +import org.apache.jetspeed.login.filter.PortalRequestWrapper; +import org.apache.jetspeed.security.AuthenticatedUser; +import org.apache.jetspeed.security.AuthenticatedUserImpl; +import org.apache.jetspeed.security.AuthenticationProvider; +import org.apache.jetspeed.security.PasswordCredential; +import org.apache.jetspeed.security.PasswordEncodingService; +import org.apache.jetspeed.security.SecurityException; +import org.apache.jetspeed.security.SubjectHelper; +import org.apache.jetspeed.security.User; +import org.apache.jetspeed.security.UserManager; + +import javax.naming.InitialContext; +import javax.security.auth.Subject; +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 javax.servlet.http.HttpSession; +import javax.sql.DataSource; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URLDecoder; +import java.security.Principal; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.Date; +import java.util.Properties; + +/** + * @author Giacomo Morri + */ +public class RememberMePortalFilter implements Filter { + + protected String guest = "guest"; + protected FilterConfig fg = null; + + protected PasswordEncodingService pes; + protected UserManager userManager; + protected AuditActivity audit; + protected AuthenticationProvider authProvider; + protected PortalAuthenticationConfiguration authenticationConfiguration; + protected UserContentCacheManager userContentCacheManager; + + protected String rememberMeCookieName = "js_at"; + + public void init(FilterConfig filterConfig) throws ServletException { + PortalConfiguration config = Jetspeed.getConfiguration(); + if (config != null) { + guest = config.getString("default.user.principal"); + rememberMeCookieName = config.getString("rmpf.accesstoken.cookie.name"); + } + fg = filterConfig; + // load components once + ComponentManager cm = Jetspeed.getComponentManager(); + pes = cm.lookupComponent("org.apache.jetspeed.security.PasswordEncodingService"); + userManager = cm.lookupComponent("org.apache.jetspeed.security.UserManager"); + audit = cm.lookupComponent("org.apache.jetspeed.audit.AuditActivity"); + authProvider = cm.lookupComponent("org.apache.jetspeed.security.AuthenticationProvider"); + authenticationConfiguration = cm.lookupComponent("org.apache.jetspeed.administration.PortalAuthenticationConfiguration"); + userContentCacheManager = cm.lookupComponent("userContentCacheManager"); + } + + protected String getTokenFromCookie(HttpServletRequest request) { + String token = null; + //reading token from cookies + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + if (cookies.length > 0) { + for (Cookie c : cookies) { + if (c.getName().equals(rememberMeCookieName)) { + token = c.getValue(); + break; + } + } + } + } + return token; + } + + public void doFilter(ServletRequest sRequest, + ServletResponse sResponse, FilterChain filterChain) + throws IOException, ServletException { + if (sRequest instanceof HttpServletRequest) { + HttpServletRequest request = (HttpServletRequest) sRequest; + HttpSession httpSession = PortalSessionValidationFilter.getValidSession(request); + + String username = null; + String password = null; + + String token = null; + + //checking if a user is already authenticated + boolean goOn = false; + Subject actualSubject = (Subject) request.getSession().getAttribute(PortalReservedParameters.SESSION_KEY_SUBJECT); + if (actualSubject != null) { + Principal principal = SubjectHelper.getPrincipal(actualSubject, User.class); + + if (principal == null || principal.getName().equals(this.guest)) { + goOn = true; + } + } else { + goOn = true; + } + + if (goOn) { + token = getTokenFromCookie(request); + if (token != null) { + token = URLDecoder.decode(token, "UTF-8"); + + if (token != null) { + username = getUsernameFromAccessToken(token); + + if (username != null) { + try { + User jetspeedUser = userManager.getUser(username); + PasswordCredential psw = userManager.getPasswordCredential(jetspeedUser); + + if (psw != null) { + + String pswencoded = psw.getPassword(); + + if (pswencoded != null) { + password = pes.decode(jetspeedUser.getName(), pswencoded); + } + } + + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + } + + if (username != null && password != null && goOn) { + + AuthenticatedUser authUser = null; + try { + authUser = authProvider.authenticate(username, password); + } catch (SecurityException e) { + audit.logUserActivity(username, request.getRemoteAddr(), AuditActivity.AUTHENTICATION_FAILURE, "PortalFilter"); + request.getSession().setAttribute(LoginConstants.ERRORCODE, LoginConstants.ERROR_INVALID_PASSWORD); + } + if (authUser != null) { + audit.logUserActivity(username, request.getRemoteAddr(), AuditActivity.AUTHENTICATION_SUCCESS, "PortalFilter"); + if (authenticationConfiguration.isCreateNewSessionOnLogin() && httpSession != null && !httpSession.isNew()) { + request.getSession().invalidate(); + } else { + userContentCacheManager.evictUserContentCache(username, request.getSession().getId()); + } + if (authUser.getUser() == null) { + try { + // load the user principals (roles, groups, credentials) + User user = userManager.getUser(username); + if (user != null) { + authUser = new AuthenticatedUserImpl(user, authUser.getPublicCredentials(), authUser.getPrivateCredentials()); + } + } catch (SecurityException sex) { + // TODO: maybe some better handling required here + throw new ServletException(sex); + } + } + Subject subject; + try { + // default solution using the build-in UserManager + subject = userManager.getSubject(authUser); + + // alternate DIY solution not using the build-in UserManager: + //subject = JetspeedSubjectFactory.createSubject(authUser.getUser(),authUser.getPrivateCredentials(),authUser.getPublicCredentials(),null); + } catch (SecurityException e) { + // TODO: maybe some better handling required here + throw new ServletException(e); + } + sRequest = wrapperRequest(request, subject, authUser.getUser()); + request.getSession().removeAttribute(LoginConstants.ERRORCODE); + HttpSession session = request.getSession(true); + session.setAttribute(PortalReservedParameters.SESSION_KEY_SUBJECT, subject); + + //setting login by token attribute in request + // FIXME: request.setAttribute(Constants.REQUEST_ATTRIBUTE_LOGIN_BY_TOKEN, "true"); + + //updating token expiration date (+6 months) + updateTokenExpDate(token); + + } else { + audit.logUserActivity(username, request.getRemoteAddr(), AuditActivity.AUTHENTICATION_FAILURE, "PortalFilter"); + request.getSession().setAttribute(LoginConstants.ERRORCODE, LoginConstants.ERROR_INVALID_PASSWORD); + } + } else { + Subject subject = (Subject) request.getSession().getAttribute(PortalReservedParameters.SESSION_KEY_SUBJECT); + if (subject != null) { + Principal principal = SubjectHelper.getPrincipal(subject, User.class); + if (principal != null && principal.getName().equals(this.guest)) { + } else { + sRequest = wrapperRequest(request, subject, principal); + } + } + } + + } + + if (filterChain != null) { + filterChain.doFilter(sRequest, sResponse); + } + } + + /** + * This requires additional tables: + * user_token + * user + * + * @param token + * @return + */ + private String getUsernameFromAccessToken(String token) { + String username = null; + + Connection connection = null; + Statement stmt = null; + ResultSet result = null; + + InitialContext ic; + try { + + String userId = null; + + // getting DataSource from Jetspeed + ic = new InitialContext(); + DataSource ds = (DataSource) ic.lookup("java:comp/env/jdbc/jetspeed"); + + if (ds != null) { + connection = ds.getConnection(); + stmt = connection.createStatement(); + + result = stmt.executeQuery("SELECT id,userid,date_expiry FROM user_token WHERE token_value= '" + token + "'"); + + int count = 1; + boolean isValid = false; + Date expDate = null; + String tokenId = null; + + // only the first result is loaded + while (result.next() && count <= 1) { + + tokenId = result.getString("id"); + userId = result.getString("userid"); + expDate = result.getDate("date_expiry"); + + count++; + } + + result.close(); + + // check expiration date + if (expDate != null) { + Date actualDate = new Date(); + if (actualDate.before(expDate)) { + isValid = true; + } else { + //token expired, delete it + stmt.executeUpdate("DELETE FROM user_token WHERE id= '" + tokenId + "'"); + } + } + + if (userId != null && isValid) { + + result = stmt.executeQuery("SELECT jetspeed_username FROM user WHERE id= '" + userId + "'"); + + count = 1; + + // only the first result is loaded + while (result.next() && count <= 1) { + + username = result.getString("jetspeed_username"); + + count++; + } + + result.close(); + + } + + stmt.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (result != null) + result.close(); + + if (stmt != null) + stmt.close(); + + if (connection != null) + connection.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + return username; + } + + private void updateTokenExpDate(String token) { + + Connection connection = null; + Statement stmt = null; + ResultSet result = null; + + InitialContext ic; + try { + + // getting DataSource from Jetspeed + ic = new InitialContext(); + DataSource ds = (DataSource) ic.lookup("java:comp/env/jdbc/jetspeed"); + + if (ds != null) { + connection = ds.getConnection(); + stmt = connection.createStatement(); + + result = stmt.executeQuery("SELECT id FROM user_token WHERE token_value= '" + token + "'"); + + int count = 1; + String tokenId = null; + + // only the first result is loaded + while (result.next() && count <= 1) { + + tokenId = result.getString("id"); + + count++; + } + + result.close(); + + // check expiration date + if (tokenId != null) { + + PreparedStatement pstmt = connection.prepareStatement("UPDATE user_token SET date_expiry = ? WHERE id= '" + tokenId + "'"); + Date actualDate = new Date(); + Date expDate = DateUtils.addMonths(actualDate, 6); + pstmt.setDate(1, new java.sql.Date(expDate.getTime())); + pstmt.executeUpdate(); + + } + + stmt.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (result != null) + result.close(); + + if (stmt != null) + stmt.close(); + + if (connection != null) + connection.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + + private ServletRequest wrapperRequest(HttpServletRequest request, Subject subject, Principal principal) { + PortalRequestWrapper wrapper = new PortalRequestWrapper(request, subject, principal); + return wrapper; + } + + public void destroy() { + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: jetspeed-dev-unsubscr...@portals.apache.org For additional commands, e-mail: jetspeed-dev-h...@portals.apache.org