001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.security.impl.jacc;
023:
024: import org.jboss.logging.Logger;
025: import org.jboss.portal.security.PortalPermission;
026: import org.jboss.portal.security.PortalSecurityException;
027: import org.jboss.portal.security.SecurityConstants;
028: import org.jboss.portal.security.spi.auth.PortalAuthorizationManager;
029: import org.jboss.portal.security.spi.provider.AuthorizationDomain;
030: import org.jboss.portal.security.spi.provider.PermissionFactory;
031:
032: import javax.security.auth.Subject;
033: import javax.security.jacc.PolicyConfigurationFactory;
034: import javax.security.jacc.PolicyContext;
035: import javax.security.jacc.PolicyContextException;
036: import java.security.Principal;
037: import java.security.ProtectionDomain;
038: import java.util.Collection;
039: import java.util.Iterator;
040: import java.util.Map;
041: import java.util.Set;
042:
043: /**
044: * Portal Authorization Manager based on JACC Has deep integration with the JBossSX Jacc Layer.
045: *
046: * @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a>
047: * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
048: * @since Jan 30, 2006
049: */
050: public class JACCPortalAuthorizationManager implements
051: PortalAuthorizationManager {
052:
053: /** . */
054: private static Logger log = Logger
055: .getLogger(JACCPortalAuthorizationManager.class);
056:
057: /** . */
058: private static final boolean trace = log.isTraceEnabled();
059:
060: /** . */
061: private final JACCPortalAuthorizationManagerFactory factory;
062:
063: /** . */
064: private PolicyConfigurationFactory pcf;
065:
066: /** Used to retrieve the subject in hte jacc portal permission collection. */
067: private static final ThreadLocal checkedSubjectLocal = new ThreadLocal();
068:
069: /** JACC bypass */
070: private SecurityContext securityContext = null;
071:
072: /**
073: * JACC bypass
074: *
075: * @param securityContext
076: */
077: void setSecurityContext(SecurityContext securityContext) {
078: this .securityContext = securityContext;
079: }
080:
081: public JACCPortalAuthorizationManager(
082: JACCPortalAuthorizationManagerFactory factory) {
083: this .factory = factory;
084: try {
085: pcf = PolicyConfigurationFactory
086: .getPolicyConfigurationFactory();
087: } catch (Exception e) {
088: log.error(
089: "Unable to obtain the PolicyConfigurationFactory",
090: e);
091: }
092: }
093:
094: public void checkRoleConfig(String contextID, String roleName)
095: throws PortalSecurityException {
096: /*Map configuredRoles = factory.configuredRoles;
097: synchronized (configuredRoles)
098: {
099: // The policy configuration
100: PolicyConfiguration pc = null;
101: try
102: {
103: try
104: {
105: if (!configuredRoles.containsKey(roleName))
106: {
107: // Iterate over all domains to add their container
108: Collection domains = factory.getAuthorizationDomainRegistry().getDomains();
109: for (Iterator j = domains.iterator(); j.hasNext();)
110: {
111: AuthorizationDomain domain = (AuthorizationDomain)j.next();
112: JACCPortalPermissionCollection collection = new JACCPortalPermissionCollection(roleName, domain);
113: PermissionFactory permissionFactory = domain.getPermissionFactory();
114: PortalPermission container = permissionFactory.createPermissionContainer(collection);
115:
116: if (pc == null)
117: {
118: pc = pcf.getPolicyConfiguration(contextID, false);
119: }
120:
121: if (SecurityConstants.UNCHECKED_ROLE_NAME.equals(roleName))
122: {
123: pc.addToUncheckedPolicy(container);
124: }
125: else
126: {
127: pc.addToRole(roleName, container);
128: }
129: }
130:
131: //
132: configuredRoles.put(roleName, roleName);
133: }
134: }
135: catch (PolicyContextException e)
136: {
137: throw new PortalSecurityException(e);
138: }
139: }
140: finally
141: {
142: // JBossSX implies check does not happen until the PC has committed
143: // and the policy has been refreshed
144: try
145: {
146: if (pc != null && !pc.inService())
147: {
148: pc.commit();
149: Policy.getPolicy().refresh();
150: }
151: }
152: catch (PolicyContextException e)
153: {
154: log.error("Error when commiting policy config", e);
155: }
156: }
157: }*/
158:
159: /**
160: * JACC bypass
161: */
162: Map configuredRoles = factory.configuredRoles;
163: synchronized (configuredRoles) {
164: if (!configuredRoles.containsKey(roleName)) {
165: // Iterate over all domains to add their container
166: Collection domains = factory
167: .getAuthorizationDomainRegistry().getDomains();
168: for (Iterator j = domains.iterator(); j.hasNext();) {
169: AuthorizationDomain domain = (AuthorizationDomain) j
170: .next();
171: JACCPortalPermissionCollection collection = new JACCPortalPermissionCollection(
172: roleName, domain);
173: PermissionFactory permissionFactory = domain
174: .getPermissionFactory();
175: PortalPermission container = permissionFactory
176: .createPermissionContainer(collection);
177:
178: if (SecurityConstants.UNCHECKED_ROLE_NAME
179: .equals(roleName)) {
180: this .securityContext
181: .addToUncheckedPolicy(container);
182: } else {
183: this .securityContext.addToRole(roleName,
184: container);
185: }
186: }
187: configuredRoles.put(roleName, roleName);
188: }
189: }
190: }
191:
192: /**
193: * @throws IllegalArgumentException if the permission is null
194: * @throws PortalSecurityException
195: */
196: private boolean internalCheckPermission(PortalPermission permission)
197: throws IllegalArgumentException, PortalSecurityException {
198: if (permission == null) {
199: throw new IllegalArgumentException(
200: "No null permission can be checked");
201: }
202:
203: // Get the current context id.
204: String contextID = PolicyContext.getContextID();
205:
206: //
207: if (contextID == null) {
208: throw new PortalSecurityException("No policy context id");
209: }
210:
211: // Get the current authenticated subject through the JACC contract
212: Subject currentSubject = (Subject) checkedSubjectLocal.get();
213:
214: //
215: Principal[] principals;
216:
217: // Always check the unckeded permission container
218: checkRoleConfig(contextID,
219: SecurityConstants.UNCHECKED_ROLE_NAME);
220:
221: //
222: if (currentSubject != null) {
223: Set tmp = currentSubject
224: .getPrincipals(JACCPortalPrincipal.class);
225: JACCPortalPrincipal pp = null;
226: for (Iterator i = tmp.iterator(); i.hasNext();) {
227: pp = (JACCPortalPrincipal) i.next();
228: if (pp != null) {
229: break;
230: }
231: }
232: if (pp == null) {
233: pp = new JACCPortalPrincipal(currentSubject);
234: tmp.add(pp);
235:
236: // Lazy create all the permission containers for the given role names
237: for (Iterator i = pp.getRoles().iterator(); i.hasNext();) {
238: Principal role = (Principal) i.next();
239: checkRoleConfig(contextID, role.getName());
240:
241: if (trace) {
242: log.trace("Internal check. Contains role: "
243: + role.getName());
244: }
245: }
246: }
247: principals = pp.getPrincipals();
248: } else {
249: principals = new Principal[0];
250: }
251:
252: //Bypass the JACC layer and go straight to the portal security permission layer
253: /*ProtectionDomain pd = new ProtectionDomain(null, null, null, principals);
254: Policy policy = Policy.getPolicy();
255: boolean implied = policy.implies(pd, permission);*/
256:
257: /**
258: * alternately bypassing the call and not letting it go through the
259: * JACC system.
260: *
261: * There is not an issue with JBoss JACC implementation, but the Permissions object
262: * in JDK5 which is leveraged by JACC. The synchrnozied block inside Permissions object
263: * is causing performance bottleneck
264: */
265: ProtectionDomain pd = new ProtectionDomain(null, null, null,
266: principals);
267: boolean implied = this .securityContext.implies(pd, permission);
268:
269: return implied;
270: }
271:
272: public boolean checkPermission(Subject checkedSubject,
273: PortalPermission permission)
274: throws IllegalArgumentException, PortalSecurityException {
275: try {
276: // Set the subject for later use in that layer
277: checkedSubjectLocal.set(checkedSubject);
278:
279: if (trace && checkedSubject != null) {
280: for (Principal principal : checkedSubject
281: .getPrincipals()) {
282: log.trace("Principal name: " + principal.getName());
283: }
284:
285: }
286: //
287: if (trace) {
288: log.trace("hasPermission:name=" + permission.getName()
289: + "uri=" + permission.getURI() + "::actions="
290: + permission.getActions() + "::type="
291: + permission.getType());
292: }
293:
294: //
295: boolean result = internalCheckPermission(permission);
296:
297: //
298: if (trace) {
299: log.trace("hasPermission:result=" + result);
300: }
301:
302: //
303: return result;
304: } finally {
305: checkedSubjectLocal.set(null);
306: }
307: }
308:
309: public boolean checkPermission(PortalPermission permission)
310: throws IllegalArgumentException, PortalSecurityException {
311: try {
312: // Get the current authenticated subject through the JACC contract
313: Subject subject = (Subject) PolicyContext
314: .getContext("javax.security.auth.Subject.container");
315:
316: //
317: return checkPermission(subject, permission);
318: } catch (PolicyContextException e) {
319: throw new PortalSecurityException(e);
320: }
321: }
322:
323: static Subject getCheckedSubject() {
324: return (Subject) checkedSubjectLocal.get();
325: }
326: }
|