This is a continuation of the discussion at
http://mail-archives.apache.org/mod_mbox/cxf-dev/200808.mbox/[EMAIL PROTECTED]
I've confirmed that this is still an issue in 2.2-SNAPSHOT, and I'd
like to start a discussion of solutions. I'll start by describing the
policy framework architecture, as I understand it, but I'll focus on
the server-side of a CXF request and response, when policy is
involved. This should give enough context to form a discussion of how
to proceed.
Generally, the way the CXF policy framework works is as follows
(please chime in if I've gotten any details wrong). When the policy
framework is loaded, at least 2 interceptors are installed on the
interceptor chain (and again, let's just focus, for the time being, on
the inbound server request and outbound server response):
* ServerPolicy(In|Out)Interceptor
* PolicyVerification(In|Out)Interceptor
The role of the ServerPolicy*Interceptors are to:
1. Establish the "effective" policy for the request/response, based
off a collection of policy sources (WSDL, Spring, etc)
2. Select a set of policy assertion alternatives, using an
alternative selector (defined essentially at Bus granularity)
3. Construct an AssertionInfoMap, which is basically just a map from
the policy assertion QNames out of the list of selected assertions to
the selected assertions, themselves. Think of it as a multimap. Once
constructed, the AssertionInfoMap placed on the message, for
subsequent interceptors to inspect and/or mutate.
The role of the PolicyVerification*Interceptor is to compare the
asserted policies against the effective policies, and to compute
whether the effective policy has been satisfied by the collection of
asserted policies. If the effective policy is so satisfiable, then
the request is allowed to proceed; otherwise, a fault is raised (and I
see that in 2.2, Dan has added some nice helpful information about
why). (A bug has been identified [1] in the case of faults thrown in
the PolicyVerificationOutInterceptor.)
(Between these interceptors, applications (like a WS-* provider) are
expected to inspect and/or mutate the AssertionInfo objects in the
AssertionInfoMap, to indicate that a particular policy assertion has
been satisfied in the runtime.)
Now, the server-side request and response processing is slightly
asymmetric, in the following respects:
A. When processing an inbound request, the intervening interceptors
are sandwiched by a ServerPolicyInInterceptor and a
PolicyVerificationInInterceptor, whereas the outbound response
interceptor chain is sandwiched by a ServerPolicyOutInterceptor and a
PolicyVerificationOutInterceptor
B. The AssertionInfoMap, and the association policy assertion
instances contained in them, are different instances on the inbound
request and outbound response chains. In particular, any policy
assertion instances that are "checked off" on the inbound request side
must also be checked off on the outbound response side.
C. The policy alternative selection algorithm (the
AlternativeSelector) is different on the inbound request and outbound
response sides. In particular, on the inbound request side, all
possible alternatives are selected, whereas on the outbound response
side, the default AlternativeSelector (the MinimalAlternativeSelector)
on the PolicyEngine is used, which generally picks one alternative
from a collection possibilities. As a consequence, not only are the
AssertionInfo instances on the response AssertionInfoMap different
from those on the request (B above), but the structure of the
AssertionInfoMap itself is different.
The combination of B and C actually conspires to yield another, more
serious bug.
Consider the following effective policy:
<wsp:Policy>
<wsp:ExactlyOne>
<foo:Bar/>
<gnu:Gnat/>
</wsp:ExactlyOne>
</wsp:Policy>
On the inbound request, the key set of the AssertionInfoMap will
contain the QNames:
[{foo}Bar, {gnu:Gnat}]
whereas the key set of the AssertionInfoMap on the outbound response
will contain just the QName (say):
[{foo}Bar]
Now let's say a client sends a request that satisfies <gnu:Gnat>. The
effective policy will have been satisfied on the inbound request;
however, on the outbound response, it will not. The result is a fault
raised in the PolicyVerificationOutInterceptor, though by [1], this
can easily go undetected.
So, what are the solutions?
[bad] One workaround is to set the AlternativeSelector on the
PolicyEngine to be something like the UnionAlternativeSelector that's
used on the inbound request side. That way, the AssertionInfoMap on
the outbound response will contain all the "right" QNames, and the
effective policy will be reported as being satisfied. One reason this
is bad is that the PolicyEngine is global wrt the Bus, so this sort of
change to the engine would have all sorts of nasty unintended side-
effects. Perhaps a better level of granularity would work, where you
could specify a specific policy alternative selector on a per-
interceptor-chain basis, which would mitigate the badness, a bit.
[marginally better] Copy the asserted AssertionInfo objects that have
been satisfied on the inbound request to the outbound response. The
assertions have already been checked off. Why should we need to do
this again on the outbound response? That still won't actually solve
the bug I've identified here, but it might still be a good thing to
do, nonetheless.
[better] Discriminate between inbound and outbound policies, and the
level of configuration. That way, the user can say, "here are the
inbound policies I expect/require to be satisfied on the inbound side,
and here are the policies for the outbound side". The problem with
this is that it would probably only really work when specifying
policies through Spring, since I don't think there's a way to specify
this sort of distinction in WSDL, or whatever other policy retrieval
mechanisms we support.
[not sure, but I think it's my choice] Do away with the policy
interceptors on the outbound server response, all together.
Seriously, why do we need these? What's the use-case? The only think
I can think of is something like "encrypting the response", or
something like that. However, I'm not sure there is a standard policy
that expresses this. There might be application-specific policies
that have this need, but I can't really picture them.
Thoughts on a solution?
-Fred
[1] https://issues.apache.org/jira/browse/CXF-1849