/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., 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.as.ejb3.component.allowedmethods; import org.jboss.as.ee.component.Component; import org.jboss.as.ee.component.interceptors.InvocationType; import org.jboss.as.ejb3.logging.EjbLogger; import org.jboss.as.ejb3.component.EJBComponent; import org.jboss.as.ejb3.component.stateful.CurrentSynchronizationCallback; import org.jboss.as.ejb3.context.CurrentInvocationContext; import org.jboss.invocation.InterceptorContext; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * This class and its subclasses can be used to determine if a given method * is allowed to be invoked. * * @see CurrentInvocationContext * @see CurrentSynchronizationCallback * * @author Stuart Douglas */ public class AllowedMethodsInformation { public static final AllowedMethodsInformation INSTANCE_BMT = new AllowedMethodsInformation(true); public static final AllowedMethodsInformation INSTANCE_CMT = new AllowedMethodsInformation(false); private final Set<DeniedMethodKey> denied; private final Set<DeniedSyncMethodKey> deniedSyncMethods; private final boolean beanManagedTransaction; protected AllowedMethodsInformation(boolean beanManagedTransaction) { this.beanManagedTransaction = beanManagedTransaction; final Set<DeniedMethodKey> denied = new HashSet<DeniedMethodKey>(); add(denied, InvocationType.SET_ENTITY_CONTEXT, MethodType.TIMER_SERVICE_METHOD); add(denied, InvocationType.SET_ENTITY_CONTEXT, MethodType.TIMER_SERVICE_METHOD); add(denied, InvocationType.SET_ENTITY_CONTEXT, MethodType.GET_PRIMARY_KEY); add(denied, InvocationType.SET_ENTITY_CONTEXT, MethodType.GET_TIMER_SERVICE); add(denied, InvocationType.SET_ENTITY_CONTEXT, MethodType.IS_CALLER_IN_ROLE); add(denied, InvocationType.SET_ENTITY_CONTEXT, MethodType.GET_CALLER_PRINCIPLE); add(denied, InvocationType.HOME_METHOD, MethodType.TIMER_SERVICE_METHOD); add(denied, InvocationType.HOME_METHOD, MethodType.GET_PRIMARY_KEY); add(denied, InvocationType.ENTITY_EJB_CREATE, MethodType.TIMER_SERVICE_METHOD); add(denied, InvocationType.ENTITY_EJB_CREATE, MethodType.GET_PRIMARY_KEY); setup(denied); this.denied = Collections.unmodifiableSet(denied); final Set<DeniedSyncMethodKey> deniedSync = new HashSet<DeniedSyncMethodKey>(); add(deniedSync, CurrentSynchronizationCallback.CallbackType.AFTER_COMPLETION, MethodType.TIMER_SERVICE_METHOD); add(deniedSync, CurrentSynchronizationCallback.CallbackType.AFTER_COMPLETION, MethodType.GET_ROLLBACK_ONLY); add(deniedSync, CurrentSynchronizationCallback.CallbackType.AFTER_COMPLETION, MethodType.SET_ROLLBACK_ONLY); this.deniedSyncMethods = Collections.unmodifiableSet(deniedSync); } protected void setup(Set<DeniedMethodKey> denied) { } protected static void add(Set<DeniedMethodKey> otherDenied, InvocationType setEntityContext, MethodType timerServiceMethod) { otherDenied.add(new DeniedMethodKey(setEntityContext, timerServiceMethod)); } protected static void add(Set<DeniedSyncMethodKey> otherDenied, CurrentSynchronizationCallback.CallbackType callbackType, MethodType timerServiceMethod) { otherDenied.add(new DeniedSyncMethodKey(callbackType, timerServiceMethod)); } /** * Checks that the current method */ public static void checkAllowed(final MethodType methodType) { final InterceptorContext context = CurrentInvocationContext.get(); if (context == null) { return; } final Component component = context.getPrivateData(Component.class); if (!(component instanceof EJBComponent)) { return; } final InvocationType invocationType = context.getPrivateData(InvocationType.class); ((EJBComponent) component).getAllowedMethodsInformation().realCheckPermission(methodType, invocationType); } /** * transaction sync is not affected by the current invocation, as multiple ejb methods may be invoked from afterCompletion */ private void checkTransactionSync(MethodType methodType) { //first we have to check the synchronization status //as the sync is not affected by the current invocation final CurrentSynchronizationCallback.CallbackType currentSync = CurrentSynchronizationCallback.get(); if (currentSync != null) { if (deniedSyncMethods.contains(new DeniedSyncMethodKey(currentSync, methodType))) { throwException(methodType, currentSync); } } } protected void realCheckPermission(MethodType methodType, InvocationType invocationType) { checkTransactionSync(methodType); if (invocationType != null) { if (denied.contains(new DeniedMethodKey(invocationType, methodType))) { throwException(methodType, invocationType); } } if (invocationType != InvocationType.CONCURRENT_CONTEXT && !beanManagedTransaction && methodType == MethodType.GET_USER_TRANSACTION) { throw EjbLogger.ROOT_LOGGER.unauthorizedAccessToUserTransaction(); } } /** * throw an exception when a method cannot be invoked * * @param methodType the method * @param invocationType the type of invocation that caused it to be disabled */ protected void throwException(MethodType methodType, InvocationType invocationType) { throw EjbLogger.ROOT_LOGGER.cannotCallMethod(methodType.getLabel(), invocationType.getLabel()); } /** * throw an exception when a method cannot be invoked * * @param methodType the method * @param callback the type of invocation that caused it to be disabled */ protected void throwException(MethodType methodType, CurrentSynchronizationCallback.CallbackType callback) { throw EjbLogger.ROOT_LOGGER.cannotCallMethod(methodType.getLabel(), callback.name()); } private static class DeniedSyncMethodKey { private final CurrentSynchronizationCallback.CallbackType callbackType; private final MethodType methodType; public DeniedSyncMethodKey(CurrentSynchronizationCallback.CallbackType callbackType, MethodType methodType) { this.callbackType = callbackType; this.methodType = methodType; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DeniedSyncMethodKey that = (DeniedSyncMethodKey) o; if (callbackType != that.callbackType) return false; if (methodType != that.methodType) return false; return true; } @Override public int hashCode() { int result = callbackType != null ? callbackType.hashCode() : 0; result = 31 * result + (methodType != null ? methodType.hashCode() : 0); return result; } } }