associated with a certain thread. bf:
B, a
business function.
• allow(r,bf): returns true if users in role r are
allowed to invoke business function bf.
Otherwise, the function returns false.
• allow(caller, callee, bf): this function returns
true if in the business function bf, caller
invokes callee. Otherwise, the function returns
false.
• entry(bf): this function returns the entry method
of business function bf.
• preCall(caller, callee, bf): This function returns
a set of methods so that if m
is an element of
this set then caller calls m
before invoking
callee and the business function containing
these invocations is bf.
• initBf(r, callee): callee
∈ M is the called
method. This function returns a set of business
functions so that if bf is an element of this set
then entry(bf)==callee and allow(r,bf)==true.
• nextBf(bfs, caller, callee, preMethod): bfs
⊂ B,
is the set of business functions this thread may
involve. This function returns a subset of bfs so
that if bf is an element in this subset, then
allow(caller, caller, bf)==true and
preMethod
∈
preCall(caller, callee, bf).
In the BFSec framework, the above functions are
provided by the BFInfo module. The BFControl
module uses these functions to update the set of
business functions for each thread at runtime.
However, in order to use these functions, we need to
know callee, caller, and preMethod. The next
section describes how to obtain these values at
runtime.
4.3 Obtaining Runtime Information of
Threads
In this section we describe how to obtain
information that is used for updating sets of business
functions associated with threads. We also explain
the way in which this information is managed by the
CallFlow module.
Figure 3: The solution for determining the callers.
The information about a thread that we need to
know is the callee, the caller, and the previous called
method of the caller. For the callee, we can easily
acquire because at interceptors we know which
method we are invoking. However, determining the
caller and the previous method called by the caller is
quite difficult. The solution to this problem is to
equip a stack for each thread. Figure 3 illustrates our
solution. In the figure, the stack used for the thread
is
cs. The operation on the stack includes peek():
returns the value on top of the stack;
push(m):
pushes m onto the top of the stack; pop():
removes and returns the top value of the stack.
For each thread in an application, we need to
maintain:
bfs: a set of business functions that is
associated with the thread,
cs: a stack containing
methods the thread has been invoking, and
preMethod: the method last called by the method
on the top of the
cs stack. In our framework, each
thread is provided an entry containing this
information and these entries are managed by the
CallFlow module.
In cases where the caller and the callee are
located in different machines that solution will not
work because we base it on threads. This is the
reason why we use client-side interceptors. The task
of these interceptors is to send information of
threads making the call (including the set of business
functions, the caller, and the previous called of the
caller) to the remote system. This means that when
checking permission of a remote call, instead of
obtaining information of threads from the CallFlow
module, the BFControl module will use information
sent by the client-side interceptors.
4.4 Business Function Enforcement
This section describes how the BFControl module
uses the BFInfor module and the CallFlow module
to update sets of business functions associated with
threads and to enforce call flows at runtime.
At the interceptors, the set of business functions
associated with a thread is updated as follows.
if(caller==null)
bfs=initBf(r,callee)
else
bfs=nextBf(bfs,caller,callee,
preMethod)
if(bfs==null)
return false;// invocation blocked
else
return true;// invocation allwed
Listing 3: The update of business functions associated
with a thread.
A FRAMEWORK FOR PROTECTING EJB APPLICATIONS FROM MALICIOUS COMPONENTS
267