We're currently missing $subject in WildFly and I'd like to add it in. I
regard this absence as a bug, as expression resolution functionality should
be consistent between expressions in deployment resources and those in the
management model.
The biggest hurdle to doing this is that ElytronExpressionResolver, the class
that resolves credential store expressions, requires access to an
OperationContext to do resolution, and that is not available when resolving
these deployment resource expressions. It needs the OperationContext for
what I think are 3 basic reasons:
1) So objects it uses can get the PathManager to resolve paths.
2) So it or objects it uses can resolve capabilities, e.g. to get the
runtime api exposed by the relevant credential store, which in turn does
something similar with providers.
3) So it and objects it uses can resolve their configuration settings from
the management model and initialize themselves.
The last bit is interesting as those classes can't *solely* rely on a
Stage.RUNTIME step from the OSH that adds their config model. During
parallel boot, threads that are initializing other subsystems in
Stage.RUNTIME concurrently with a different thread that is initializing the
elytron subsystem may need to initialize these objects using their own
thread's OperationContext. For example, they may need to resolve a
credential store expression in their own config model.
A key design point for what I have in mind is that AIUI there is no reason
all this initialization work can't be completed before an operation
(including boot) proceeds to dealing with deployments. During boot we do
all the Stage.RUNTIME work for subsystems before proceeding to deployments.
After boot, people creating an operation with a step that deploys a
deployment that uses a credential store expression must ensure the relevant
credential store resolver has been added first.
So, what I'm thinking of doing is:
A) Abstract the internal uses of OperationContext behind an interface, with
impls backed by either an OperationContext or a CapabilityServiceSupport.
Methods the CapabilityServiceSupport-backed impl can't support (resolving
config values) will fail in javadoced manner, probably an ISE. Callers deal
with the failure appropriately. I *believe* once all is done any such
failure would indicate a bug in WF, i.e. that things that should have been
initialized before deployment work starts haven't been.
B) Where this doesn't already happen, ensure that any Elytron resource that
adds one of these objects that gets initialized via the A) interface gets
initialized by the OperationContext that adds the resource (if some other
OperationContext hasn't already done so.) For sure
ExpressionResolverResourceDefinition
will need to be updated to ensure ElytronExpressionResolver is initialized
along with any credential stores it may rely upon. (I'm thinking of doing
this by having a Stage.RUNTIME OSH ask the ElytronExpressionResolver to
create an expression using each configured resolver.)
C) For the PathManager case, either have the impls behind A) look up the
PathManager via a capability, or make the PathManager available from the
ExtensionContext on host processes (currently it is only available there on
servers) and have that injected into the impls.
D) Add a deployment AttachmentKey that exposes an object that the EE
subsystem can use to wire credential store expression support into the
existing deployment expression resolution, a la what we did before with
vault expression resolution. Elytron subsystem would attach the object.
Probably the object would be a BiFunction<String, CapabilityServiceSupport,
String>. Perhaps we could expose this via a capability, but using a
deployment processing attachment restricts the exposure of the object to
deployment processing.
Feedback is welcome!
Best regards,
--
Brian Stansberry
Project Lead, WildFly
He/Him/His