001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kim.client.acegi; 017 018import javax.servlet.http.HttpServletRequest; 019import javax.servlet.http.HttpServletResponse; 020 021import org.acegisecurity.Authentication; 022import org.acegisecurity.AuthenticationException; 023import org.acegisecurity.GrantedAuthority; 024import org.acegisecurity.context.SecurityContextHolder; 025import org.acegisecurity.ui.cas.CasProcessingFilter; 026import org.kuali.rice.kim.sesn.DistributedSession; 027 028/** 029 * This class is the main integration point for implementing the 030 * distributed session in ACEGI. 031 * 032 * TODO: Need to add check for missing DST (update 033 * {@link org.kuali.rice.kim.sesn.DistributedSession}) 034 * 035 * @author Kuali Rice Team (rice.collab@kuali.org) 036 * @see org.acegisecurity.ui.cas.CasProcessingFilter#attemptAuthentication 037 */ 038public class KualiDistributedSessionFilter extends CasProcessingFilter { 039 040 private DistributedSession distributedSession; 041 042 //~ Methods ======================================================================================================== 043 044 /** 045 * This overridden method gets called if requiresAuthentication is true. 046 * If Session is Invalid, throw a {@link KualiDistribtedSessionExpiredException}. 047 * The session is determined invalid if the authentication is of type 048 * {@link KualiDistribtedSessionExpiredAuthentication}. Otherwise it 049 * would have to verify if the DST is valid twice. 050 * 051 * @return the authentication result of the super method 052 * @see org.acegisecurity.ui.cas.CasProcessingFilter#attemptAuthentication(javax.servlet.http.HttpServletRequest) 053 */ 054 public Authentication attemptAuthentication(final HttpServletRequest request) 055 throws AuthenticationException { 056 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 057 058 if (authentication instanceof KualiDistributedSessionExpiredAuthentication) { 059 logger.debug("Authentication is dead in attemptAuthentication, setting authentication to null and throwing KualiDistributedSessionExpiredException"); 060 SecurityContextHolder.getContext().setAuthentication(null); 061 062 throw new KualiDistributedSessionExpiredException("Session Expired"); 063 } 064 065 return super.attemptAuthentication(request); 066 } 067 068 /** 069 * This overridden method checks if the DST is valid. If it's not, the 070 * authentication is set to a new, non-authenticated, 071 * {@link KualiDistributedSessionExpiredAuthentication} which is the 072 * indication for {@link attemptAuthentication} that the session has 073 * expired 074 * 075 * @return true if DST is inValid or if super method returns true 076 * @see org.acegisecurity.ui.AbstractProcessingFilter#requiresAuthentication(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 077 */ 078 protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) { 079 boolean bSesnValid = this.isSesnValid(); 080 081 if (!bSesnValid) { 082 if (this.getDST() != null) { 083 logger.debug("session invalid, setting dead authentication, and pushing through to attemptAuthentication"); 084 SecurityContextHolder.getContext().setAuthentication(new KualiDistributedSessionExpiredAuthentication()); 085 return true; 086 } 087 } 088 089 return super.requiresAuthentication(request, response); 090 } 091 092 093 /** 094 * This method determines if the stored Distributed Session Ticket is 095 * valid. 096 * 097 * @return true if valid, false if not 098 */ 099 private boolean isSesnValid() { 100 String sDST = this.getDST(); 101 102 if (sDST != null) { 103 if (distributedSession.isSesnValid(sDST)) { 104 logger.debug("Session Valid"); 105 distributedSession.touchSesn(sDST); 106 return true; 107 } else { 108 distributedSession.clearSesn(sDST); 109 } 110 } 111 logger.debug("Session Not Valid"); 112 113 return false; 114 } 115 116 /** 117 * This method retrieves the Distributed Session Ticket 118 * 119 * @return the Distributed Session Ticket if valid or null 120 */ 121 private String getDST() { 122 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 123 String sDST = null; 124 125 if (authentication != null) { 126 GrantedAuthority[] authorities = authentication.getAuthorities(); 127 if (logger.isDebugEnabled()) { 128 logger.debug("Granted Authority Count:" + authorities.length); 129 } 130 131 for (int i = 0; i < authorities.length; i++) { 132 if (logger.isDebugEnabled()) { 133 logger.debug("Authority:" + authorities[i]); 134 } 135 if (authorities[i].toString().startsWith(DistributedSession.getPrefix())) { 136 sDST = authorities[0].toString(); 137 } 138 } 139 } 140 else { 141 logger.debug("Authentication is NULL"); 142 } 143 144 return sDST; 145 } 146 147 /** 148 * @param distributedSession the distributedSession to set 149 */ 150 public void setDistributedSession(DistributedSession distributedSession) { 151 this.distributedSession = distributedSession; 152 } 153 154}