/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.test.security.servlets; import java.io.IOException; import java.security.Principal; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.management.JMException; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.naming.InitialContext; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import javax.security.jacc.PolicyContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.jboss.mx.util.MBeanServerLocator; import org.jboss.security.SimpleGroup; import org.jboss.security.SimplePrincipal; import org.jboss.security.SubjectSecurityManager; //$Id: DeepCopySubjectServlet.java 81036 2008-11-14 13:36:39Z dimitris@jboss.org $ /** * JBAS-2657: Add option to deep copy the authenticated subject sets * Tests the Deep Copy capability for the subject sets * @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a> * @since Apr 5, 2006 * @version $Revision: 81036 $ */ public class DeepCopySubjectServlet extends HttpServlet { /** The serialVersionUID */ private static final long serialVersionUID = -277574499645473218L; private Principal anilPrincipal = TestPrincipal.getInstance(); private Principal scottPrincipal = new SimplePrincipal("scott"); protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { boolean hashCodeShouldMatch = false; //Deep Cloning case int hashCodeOfAnilPrincipal = System.identityHashCode(anilPrincipal); InitialContext context; try { String param = request.getParameter("shouldMatch"); log("param="+param); if(param == null || param.length() == 0) param = "true"; hashCodeShouldMatch = param.equals("true"); log("hashCodeShouldMatch="+hashCodeShouldMatch); //Flush the Cache - this should not have any adverse effect on the testSubject flushAuthenticationCache("deepcopy", anilPrincipal); context = new InitialContext(); SubjectSecurityManager manager = (SubjectSecurityManager)context.lookup("java:comp/env/security/securityMgr"); Subject testSubject = new Subject(); //Do a validation so that the subject gets added to the cache for the test principal log("isValid="+manager.isValid(scottPrincipal,"echoman", testSubject)); Subject authSubject = this.getAuthenticatedSubject(manager); log("AuthenticatedSubject["+authSubject+"]"); log("CopiedSubject["+testSubject+"]"); //Flush the Cache - this should not have any adverse effect on the testSubject flushAuthenticationCache("deepcopy", anilPrincipal); authSubject = this.getAuthenticatedSubject(manager); log("AuthenticatedSubject after flush["+authSubject+"]"); log("CopiedSubject after flush["+testSubject+"]"); validateSubject(testSubject, hashCodeShouldMatch, hashCodeOfAnilPrincipal); } catch (Exception e) { throw new ServletException(e); } } private Subject getAuthenticatedSubject(SubjectSecurityManager mgr) throws Exception { //First get the JACC Subject String SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container"; Subject subject = (Subject) PolicyContext.getContext(SUBJECT_CONTEXT_KEY); //Fallback if(subject == null && mgr != null) { subject = mgr.getActiveSubject(); } return subject; } /** * Validate that the subject contains the TestPrincipal and based on the * passed parameter hashCodeShouldMatch, it will check the hashcode * of the object to match with the one that was originally placed in the * subject * * @param ts Subject to Test * @param hashCodeShouldMatch Whether identityHashCode should match * @param hashCodeValueToCheck identity hashcode of the principal inserted in subject */ private void validateSubject(Subject ts, boolean hashCodeShouldMatch, int hashCodeValueToCheck) { boolean anilFound = false; Set principalSet = ts.getPrincipals(); if(principalSet == null || principalSet.isEmpty()) throw new RuntimeException("Principal Set is null"); Iterator iter = principalSet.iterator(); while(iter.hasNext()) { Principal p = (Principal)iter.next(); if(p instanceof TestPrincipal) { verifyTestPrincipal(p,hashCodeShouldMatch,hashCodeValueToCheck); anilFound = true; } } if(!anilFound) throw new RuntimeException("Test Principal not found"); } /** * Validate theTestPrincipal based on the * passed parameters hashCodeShouldMatch * @see #validateSubject(Subject, boolean, int) * @param p Principal to Test * @param hashCodeShouldMatch Whether identityHashCode should match * @param hashCodeValueToCheck identity hashcode of the principal inserted in subject */ private void verifyTestPrincipal(Principal p, boolean hashCodeShouldMatch, int hashCodeValueToCheck) { TestPrincipal tp = (TestPrincipal)p; int newHashCode = System.identityHashCode(tp); log("[hashCodeShouldMatch="+hashCodeShouldMatch+"::hashCodeValueToCheck="+ hashCodeValueToCheck + "::HashCode of TestPrincipal from copied subject="+ newHashCode+"]"); if(hashCodeShouldMatch) { if(hashCodeValueToCheck != newHashCode) throw new RuntimeException("HashCodes of the TestPrincipal do not match"); }else { if(hashCodeValueToCheck == newHashCode) throw new RuntimeException("HashCodes of the TestPrincipal are matching"); } Map map = tp.getMap(); if(map == null || map.isEmpty()) throw new RuntimeException("Map is null"); String value = (String)map.get("testKey"); if(value == null) throw new RuntimeException("Value is null"); if(!value.equals("testValue")) throw new RuntimeException("Value is not equal to testValue"); } /** * Given the security domain and the Principal, * flush the authentication cache * * @param principal * @throws JMException */ private void flushAuthenticationCache(String domain, Principal principal) throws JMException { MBeanServer server = MBeanServerLocator.locateJBoss(); ObjectName on = new ObjectName("jboss.security:service=JaasSecurityManager"); Object[] obj = new Object[] {domain, principal}; String[] sig = new String[]{"java.lang.String", "java.security.Principal"}; //Flush the Authentication Cache server.invoke(on,"flushAuthenticationCache", obj, sig); } /** * * A TestLoginModule. * All it does is it inserts a TestPrincipal that is mutable into the * subject * @author <a href="anil.saldhana@jboss.com">Anil Saldhana</a> * @version $Revision: 81036 $ */ public static class TestLoginModule implements LoginModule { public TestLoginModule() { super(); } public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { TestPrincipal tp = TestPrincipal.getInstance(); if(subject != null) { subject.getPrincipals().add(tp); } SimpleGroup sg = new SimpleGroup("Roles"); sg.addMember(new SimplePrincipal("Echo")); subject.getPrincipals().add(sg); SimpleGroup cg = new SimpleGroup("CallerPrincipal"); cg.addMember(tp); subject.getPrincipals().add(cg); } public boolean login() throws LoginException { return true; } public boolean commit() throws LoginException { return true; } public boolean abort() throws LoginException { return true; } public boolean logout() throws LoginException { return true; } } /** * * A Mutable TestPrincipal. * * @author <a href="anil.saldhana@jboss.com">Anil Saldhana</a> * @version $Revision: 81036 $ */ public static class TestPrincipal extends SimplePrincipal implements Cloneable { /** The serialVersionUID */ private static final long serialVersionUID = -6160570085301760185L; private HashMap map = new HashMap(); private static TestPrincipal _instance = new TestPrincipal("anil"); public static TestPrincipal getInstance() { return _instance; } public TestPrincipal(String name) { super(name); map.put("testKey","testValue"); } public Map getMap() { return map; } public Object clone() throws CloneNotSupportedException { TestPrincipal tp = (TestPrincipal)super.clone(); tp.map = (HashMap)this.map.clone(); return tp; } public boolean equals(Object another) { return super.equals(another); } public String toString() { return this.getName(); } } }