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.test.security.servlets;
023:
024: import java.io.IOException;
025: import java.security.Principal;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.Map;
029: import java.util.Set;
030:
031: import javax.management.JMException;
032: import javax.management.MBeanServer;
033: import javax.management.ObjectName;
034: import javax.naming.InitialContext;
035: import javax.security.auth.Subject;
036: import javax.security.auth.callback.CallbackHandler;
037: import javax.security.auth.login.LoginException;
038: import javax.security.auth.spi.LoginModule;
039: import javax.security.jacc.PolicyContext;
040: import javax.servlet.ServletException;
041: import javax.servlet.http.HttpServlet;
042: import javax.servlet.http.HttpServletRequest;
043: import javax.servlet.http.HttpServletResponse;
044:
045: import org.jboss.mx.util.MBeanServerLocator;
046: import org.jboss.security.SimpleGroup;
047: import org.jboss.security.SimplePrincipal;
048: import org.jboss.security.SubjectSecurityManager;
049:
050: //$Id: DeepCopySubjectServlet.java 57211 2006-09-26 12:39:46Z dimitris@jboss.org $
051:
052: /**
053: * JBAS-2657: Add option to deep copy the authenticated subject sets
054: * Tests the Deep Copy capability for the subject sets
055: * @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a>
056: * @since Apr 5, 2006
057: * @version $Revision: 57211 $
058: */
059: public class DeepCopySubjectServlet extends HttpServlet {
060: /** The serialVersionUID */
061: private static final long serialVersionUID = -277574499645473218L;
062:
063: private Principal anilPrincipal = TestPrincipal.getInstance();
064: private Principal scottPrincipal = new SimplePrincipal("scott");
065:
066: protected void service(HttpServletRequest request,
067: HttpServletResponse response) throws ServletException,
068: IOException {
069: boolean hashCodeShouldMatch = false; //Deep Cloning case
070:
071: int hashCodeOfAnilPrincipal = System
072: .identityHashCode(anilPrincipal);
073:
074: InitialContext context;
075: try {
076: String param = request.getParameter("shouldMatch");
077: log("param=" + param);
078: if (param == null || param.length() == 0)
079: param = "true";
080: hashCodeShouldMatch = param.equals("true");
081:
082: log("hashCodeShouldMatch=" + hashCodeShouldMatch);
083: //Flush the Cache - this should not have any adverse effect on the testSubject
084: flushAuthenticationCache("deepcopy", anilPrincipal);
085: context = new InitialContext();
086: SubjectSecurityManager manager = (SubjectSecurityManager) context
087: .lookup("java:comp/env/security/securityMgr");
088: Subject testSubject = new Subject();
089: //Do a validation so that the subject gets added to the cache for the test principal
090: log("isValid="
091: + manager.isValid(scottPrincipal, "echoman",
092: testSubject));
093: Subject authSubject = this .getAuthenticatedSubject(manager);
094: log("AuthenticatedSubject[" + authSubject + "]");
095: log("CopiedSubject[" + testSubject + "]");
096: //Flush the Cache - this should not have any adverse effect on the testSubject
097: flushAuthenticationCache("deepcopy", anilPrincipal);
098: authSubject = this .getAuthenticatedSubject(manager);
099: log("AuthenticatedSubject after flush[" + authSubject + "]");
100: log("CopiedSubject after flush[" + testSubject + "]");
101: validateSubject(testSubject, hashCodeShouldMatch,
102: hashCodeOfAnilPrincipal);
103: } catch (Exception e) {
104: throw new ServletException(e);
105: }
106: }
107:
108: private Subject getAuthenticatedSubject(SubjectSecurityManager mgr)
109: throws Exception {
110: //First get the JACC Subject
111: String SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container";
112: Subject subject = (Subject) PolicyContext
113: .getContext(SUBJECT_CONTEXT_KEY);
114:
115: //Fallback
116: if (subject == null && mgr != null) {
117: subject = mgr.getActiveSubject();
118: }
119: return subject;
120: }
121:
122: /**
123: * Validate that the subject contains the TestPrincipal and based on the
124: * passed parameter hashCodeShouldMatch, it will check the hashcode
125: * of the object to match with the one that was originally placed in the
126: * subject
127: *
128: * @param ts Subject to Test
129: * @param hashCodeShouldMatch Whether identityHashCode should match
130: * @param hashCodeValueToCheck identity hashcode of the principal inserted in subject
131: */
132: private void validateSubject(Subject ts,
133: boolean hashCodeShouldMatch, int hashCodeValueToCheck) {
134: boolean anilFound = false;
135:
136: Set principalSet = ts.getPrincipals();
137: if (principalSet == null || principalSet.isEmpty())
138: throw new RuntimeException("Principal Set is null");
139: Iterator iter = principalSet.iterator();
140: while (iter.hasNext()) {
141: Principal p = (Principal) iter.next();
142: if (p instanceof TestPrincipal) {
143: verifyTestPrincipal(p, hashCodeShouldMatch,
144: hashCodeValueToCheck);
145: anilFound = true;
146: }
147: }
148: if (!anilFound)
149: throw new RuntimeException("Test Principal not found");
150: }
151:
152: /**
153: * Validate theTestPrincipal based on the
154: * passed parameters hashCodeShouldMatch
155: * @see #validateSubject(Subject, boolean, int)
156: * @param p Principal to Test
157: * @param hashCodeShouldMatch Whether identityHashCode should match
158: * @param hashCodeValueToCheck identity hashcode of the principal inserted in subject
159: */
160: private void verifyTestPrincipal(Principal p,
161: boolean hashCodeShouldMatch, int hashCodeValueToCheck) {
162: TestPrincipal tp = (TestPrincipal) p;
163: int newHashCode = System.identityHashCode(tp);
164: log("[hashCodeShouldMatch=" + hashCodeShouldMatch
165: + "::hashCodeValueToCheck=" + hashCodeValueToCheck
166: + "::HashCode of TestPrincipal from copied subject="
167: + newHashCode + "]");
168: if (hashCodeShouldMatch) {
169: if (hashCodeValueToCheck != newHashCode)
170: throw new RuntimeException(
171: "HashCodes of the TestPrincipal do not match");
172: } else {
173: if (hashCodeValueToCheck == newHashCode)
174: throw new RuntimeException(
175: "HashCodes of the TestPrincipal are matching");
176: }
177: Map map = tp.getMap();
178: if (map == null || map.isEmpty())
179: throw new RuntimeException("Map is null");
180: String value = (String) map.get("testKey");
181: if (value == null)
182: throw new RuntimeException("Value is null");
183: if (!value.equals("testValue"))
184: throw new RuntimeException(
185: "Value is not equal to testValue");
186: }
187:
188: /**
189: * Given the security domain and the Principal,
190: * flush the authentication cache
191: *
192: * @param principal
193: * @throws JMException
194: */
195: private void flushAuthenticationCache(String domain,
196: Principal principal) throws JMException {
197: MBeanServer server = MBeanServerLocator.locateJBoss();
198: ObjectName on = new ObjectName(
199: "jboss.security:service=JaasSecurityManager");
200: Object[] obj = new Object[] { domain, principal };
201: String[] sig = new String[] { "java.lang.String",
202: "java.security.Principal" };
203:
204: //Flush the Authentication Cache
205: server.invoke(on, "flushAuthenticationCache", obj, sig);
206: }
207:
208: /**
209: *
210: * A TestLoginModule.
211: * All it does is it inserts a TestPrincipal that is mutable into the
212: * subject
213: * @author <a href="anil.saldhana@jboss.com">Anil Saldhana</a>
214: * @version $Revision: 57211 $
215: */
216: public static class TestLoginModule implements LoginModule {
217: public TestLoginModule() {
218: super ();
219: }
220:
221: public void initialize(Subject subject,
222: CallbackHandler callbackHandler, Map sharedState,
223: Map options) {
224: TestPrincipal tp = TestPrincipal.getInstance();
225: if (subject != null) {
226: subject.getPrincipals().add(tp);
227: }
228:
229: SimpleGroup sg = new SimpleGroup("Roles");
230: sg.addMember(new SimplePrincipal("Echo"));
231: subject.getPrincipals().add(sg);
232: SimpleGroup cg = new SimpleGroup("CallerPrincipal");
233: cg.addMember(tp);
234: subject.getPrincipals().add(cg);
235: }
236:
237: public boolean login() throws LoginException {
238: return true;
239: }
240:
241: public boolean commit() throws LoginException {
242: return true;
243: }
244:
245: public boolean abort() throws LoginException {
246: return true;
247: }
248:
249: public boolean logout() throws LoginException {
250: return true;
251: }
252: }
253:
254: /**
255: *
256: * A Mutable TestPrincipal.
257: *
258: * @author <a href="anil.saldhana@jboss.com">Anil Saldhana</a>
259: * @version $Revision: 57211 $
260: */
261: public static class TestPrincipal extends SimplePrincipal implements
262: Cloneable {
263: /** The serialVersionUID */
264: private static final long serialVersionUID = -6160570085301760185L;
265:
266: private HashMap map = new HashMap();
267:
268: private static TestPrincipal _instance = new TestPrincipal(
269: "anil");
270:
271: public static TestPrincipal getInstance() {
272: return _instance;
273: }
274:
275: public TestPrincipal(String name) {
276: super (name);
277: map.put("testKey", "testValue");
278: }
279:
280: public Map getMap() {
281: return map;
282: }
283:
284: public Object clone() throws CloneNotSupportedException {
285: TestPrincipal tp = (TestPrincipal) super .clone();
286: tp.map = (HashMap) this .map.clone();
287: return tp;
288: }
289:
290: public boolean equals(Object another) {
291: return super .equals(another);
292: }
293:
294: public String toString() {
295: return this.getName();
296: }
297: }
298: }
|