001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.web.tomcat.security;
023:
024: import java.security.Principal;
025: import java.security.acl.Group;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Set;
029:
030: import javax.management.JMException;
031: import javax.management.MBeanServer;
032: import javax.management.ObjectName;
033: import javax.naming.InitialContext;
034: import javax.security.auth.Subject;
035: import javax.security.jacc.PolicyContext;
036: import javax.servlet.http.HttpSessionEvent;
037: import javax.servlet.http.HttpSessionListener;
038:
039: import org.jboss.logging.Logger;
040: import org.jboss.mx.util.MBeanServerLocator;
041: import org.jboss.security.SubjectSecurityManager;
042:
043: /**
044: * JBAS-2151: Look into implementing flushOnSessionInvalidation
045: * using a session listener
046: * @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a>
047: * @since Jan 13, 2006
048: * @version $Revision: 57206 $
049: */
050: public class SecurityFlushSessionListener implements
051: HttpSessionListener {
052: private static Logger log = Logger
053: .getLogger(SecurityFlushSessionListener.class);
054:
055: private boolean trace = log.isTraceEnabled();
056:
057: private String securityDomain = null;
058:
059: /**
060: *
061: * Create a new SecurityFlushSessionListener.
062: *
063: */
064: public SecurityFlushSessionListener() {
065: }
066:
067: public void sessionCreated(HttpSessionEvent httpSessionEvent) {
068: if (trace)
069: log.trace("Session Created with id="
070: + httpSessionEvent.getSession().getId());
071: }
072:
073: public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
074: if (trace)
075: log.trace("Session Destroy with id="
076: + httpSessionEvent.getSession().getId());
077: try {
078: Subject subject = getSubjectAndSecurityDomain();
079: if (trace)
080: log.trace("securityDomain=" + securityDomain);
081: if (securityDomain == null)
082: log.debug("Unable to obtain SecurityDomain");
083: Principal principal = getPrincipal(subject);
084: if (principal != null && securityDomain != null)
085: flushAuthenticationCache(principal);
086: } catch (Exception e) {
087: log.error("Exception in sessionDestroyed:", e);
088: }
089: }
090:
091: /**
092: * Given the security domain and the Principal,
093: * flush the authentication cache
094: *
095: * @param principal
096: * @throws JMException
097: */
098: private void flushAuthenticationCache(Principal principal)
099: throws JMException {
100: MBeanServer server = MBeanServerLocator.locateJBoss();
101: ObjectName on = new ObjectName(
102: "jboss.security:service=JaasSecurityManager");
103: Object[] obj = new Object[] { securityDomain, principal };
104: String[] sig = new String[] { "java.lang.String",
105: "java.security.Principal" };
106: if (trace)
107: logAuthenticatedPrincipals(on, true);
108:
109: //Flush the Authentication Cache
110: server.invoke(on, "flushAuthenticationCache", obj, sig);
111: if (trace)
112: logAuthenticatedPrincipals(on, false);
113: }
114:
115: /**
116: * Get the Principal given the authenticated Subject
117: * Currently the first principal that is not of type
118: * java.security.acl.Group is considered
119: *
120: * @param subject
121: * @return the authenticated principal
122: */
123: private Principal getPrincipal(Subject subject) {
124: Principal principal = null;
125: if (subject != null) {
126: Set principals = subject.getPrincipals();
127: if (principals != null || !principals.isEmpty()) {
128: Iterator iter = principals.iterator();
129: while (iter.hasNext()) {
130: principal = (Principal) iter.next();
131: if (principal instanceof Group == false)
132: break;
133: }
134: }
135: }
136: if (trace)
137: log.trace("Authenticated Principal=" + principal);
138: return principal;
139: }
140:
141: /**
142: * Method that sets the securityDomain
143: * and then returns the authenticated subject
144: * First preference is given to the subject available
145: * from the Jacc SubjectContextPolicyContextHandler.
146: * As, a fallback, the Subject is obtained from the
147: * Security Manager Service
148: *
149: * @return
150: */
151: private Subject getSubjectAndSecurityDomain() throws Exception {
152: SubjectSecurityManager mgr = null;
153: try {
154: mgr = getSecurityManagerService();
155: } catch (Exception e) {
156: log.debug("Obtaining SecurityManagerService failed::", e);
157: }
158: //First get the JACC Subject
159: String SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container";
160: Subject subject = (Subject) PolicyContext
161: .getContext(SUBJECT_CONTEXT_KEY);
162: if (trace)
163: log.trace("Jacc Subject = " + subject);
164: if (mgr != null)
165: securityDomain = mgr.getSecurityDomain();
166:
167: //Fallback
168: if (subject == null && mgr != null) {
169: subject = mgr.getActiveSubject();
170: if (trace)
171: log.trace("Active Subject from security mgr service = "
172: + subject);
173: }
174: return subject;
175: }
176:
177: /**
178: * Get the Security Manager Service
179: *
180: * @return
181: * @throws Exception
182: */
183: private SubjectSecurityManager getSecurityManagerService()
184: throws Exception {
185: //Get the SecurityManagerService from JNDI
186: InitialContext ctx = new InitialContext();
187: return (SubjectSecurityManager) ctx
188: .lookup("java:comp/env/security/securityMgr");
189: }
190:
191: /**
192: * Method used to log authenticated principals
193: * remaining in cache (only when TRACE level logging is enabled)
194: *
195: * @param on ObjectName of the JaasSecurityManagerService
196: * @param isBeforeFlush Is the logging done before the auth cache flush
197: */
198: private void logAuthenticatedPrincipals(ObjectName on,
199: boolean isBeforeFlush) throws JMException {
200: if (isBeforeFlush)
201: log.trace("Before flush of authentication cache::");
202: else
203: log.trace("After flush of authentication cache::");
204: MBeanServer server = MBeanServerLocator.locateJBoss();
205:
206: List list = (List) server.invoke(on,
207: "getAuthenticationCachePrincipals",
208: new Object[] { securityDomain },
209: new String[] { "java.lang.String" });
210:
211: int len = list != null ? list.size() : 0;
212: log
213: .trace("Number of authenticated principals remaining in cache="
214: + len);
215: for (int i = 0; i < len; i++)
216: log
217: .trace("Authenticated principal in cache="
218: + list.get(i));
219: }
220: }
|