SAML 1.1 SSO sketched out

Brent Putman putmanb at georgetown.edu
Fri Jan 17 20:44:10 EST 2014


On 12/27/13 7:32 PM, Cantor, Scott wrote:
> https://wiki.shibboleth.net/confluence/display/IDP30/SAML+1.1+Browser+SSO
>
> There are a number of design questions, mostly needing discussion with
> Brent once he's back from vacation, but a lot of the code is already there
> from Chad's work and just needs cleanup.
>


Here's my first pass comments on this. Apologies for the length. Mostly
it's on the beginning and end of flow where OpenSAML is heavily
involved.  Most of the stuff in the middle I think either sounds fine,
or I don't know enough about it to comment intelligently.


** Preamble / Decode / Configuration Lookup **

The big thing here is the message handler chain that runs via
WebFlowMessageHandlerAdaptor.  Scott already mentions the need to have
the metadata resolved early b/c the message handlers need to use
metadata, but it gets worse... Scott and I discussed the following a bit
back in the Spring in Arlington, but we've never fleshed this out, so I
guess now's the time.

Essentially:  the MessageHandler(-Chain) that actually runs here needs
to be dynamically selected, it's not a static thing.  At least, it does
if we want any semblance to what v2 supported.  It was/is specific to a
relying party config and profile config.

For comparison, in v2 see the SecurityPolicyResolver and its
IdP-specific impl RelyingPartySecurityPolicyResolver.  The latter uses
the inbound message issuer's entityID and the configured profile ID to
lookup the correct SecurityPolicy to apply, using the
RelyingPartyConfigurationManager.  The SecurityPolicy lives on the
ProfileConfiguration in v2.  The SecurityPolicyResolver gets set on the
v2 MessageContext and is executed by the message decoder (which in v2,
unlike in v3, is responsible for applying the security policy on the
inbound message).

Based on the current code, and what Scott and I had preliminarily
discussed: the WebFlowMessageHandlerAdaptor  would get injected with a
special MessageHandler impl that would use inbound message data (from
MessageContext) to resolve the MessageHandler(-Chain) to run, and then
run it.  In order to do this resolution, it would need access to the
relying party and profile config info, and something would have to tell
the flow (statically I guess) what the profile ID was and so forth.  So
this "resolving MessageHandler proxy" would necessarily live in the IdP.

I don't think this is terribly hard code-wise, esp since we already have
pretty much the same model from v2.  Just need a
"MessageHandlerResolver"  component that gets injected with the thing
that can resolve RelyingPartyConfigurations (what is this in v3?). 
Looks like what's missing is that we don't have any slot currently on
the v3 ProfileConfiguration to hold a MessageHandler(-Chain).  And then
we'd need to decide how this code knows or looks up the profile ID in
use (maybe we already have a context where for where that lives, haven't
gotten that far in my code review). 

Moving on from there: CheckMandatoryIssuer. Scott questions whether we
need it.  In v2 this runs at the end of the security policy, and I would
think that if we do this check at all, we could just do it as a
MessageHandler in the inbound chain.  (This action was left over from
Chad, who saw everything as an action, but we've somewhat changed from
that).  I had meant to do a SAML-specific version of this in
opensaml-saml-impl, but looks like I didn't yet. It's probably 6 lines
of code.  It would verify the presence of a
SAMLPeerEntityContext#getEntityId().

A related comment regarding the BasicMessageMetadataContext is:  It had
been my intention that at a minimum, the messageIssuer property there
would go away, in favor of the more protocol/spec-specific way of
identifying actors (e.g. SAMLPeerEntityContext), which then gets copied
into the other subsystems' contexts where and as needed.  It's been on
my todo list, but there was a lot in the IdP that referenced it and
hadn't tackled it yet. 

MessageContext children:  I'll work on a write-up of this next week.  In
general, Scott mentions the need to populate these.  One thing to note
is that a lot of the SAML-specific message contexts intended to be used
as direct children of MessageContext are "smart", and know how to lookup
info from the SAML message in the MessageContext#getMessage().  See for
example SAMLPeerEntityContext, SAMLMessageInfoContext,
SAMLSubjectNameIdentifierContext.  The goal was to avoid needing to have
explicit handler/action code that populated these as simple bean
properties.  So you can just take advantage of subcontext autocreate,
grab one of these from the MessageContext and access the relevant
message data, with nothing else needed.


** Response Generation **

As we discussed recently and Scott mentions, the plan currently is to go
with outside-in as far as building things up.  This sounds fine, but it
did occur to me, for the Response:  I guess you start out by building it
up by assuming "success".  But what happens in the case of an error
later in the flow, where you're going to return a non-success SAML
protocol message?  Do you reuse what you were building, or do you start
from scratch?  I guess this gets in to the whole error handling aspects
of the flows, and I'm interested to see how we're going to do that, esp
things like handling outbound message signing and other outbound message
handling stuff on the error flow (as in: reuse the same outbound message
handler and encoders, etc, or have separate ones).


** Post Processing / Encode **

I guess the big question here is how we're going to do the dynamic
encoder selection for SAML front-channel, since that's based on the
binding URI selected at runtime.  As Scott notes, I had come up with 2
main approaches to that.

The first is essentially WebFlow-centric:  You have a distinct message
encoder action for each binding you support.   You select which action
you use based on a <transition> expression.  The latter would have to
evaluation something available to it, so for example something might
populate a "bindingURI" property on the flowScope.

The second is to have a single message encoder action which is injected
with a Spring-aware component that looks up the MessageEncoder instance
(which is a prototype bean) based on the binding URI.  I came up with 2
ways to implement the lookup: A) one with a simple map, similar to what
we had in v2, except that the map values are bean ids rather than actual
bean instances) and B) use a naming convention to translate binding URIs
-> bean names, and take advantage of bean aliases (<bean name="..."
/>).  The draft impl in the testbed of the lookup component supports
both (idp.SpringAwareEncoderLookup).

These 2 (really 3) are sketched out in the testbed, but since they're
all there, it may not be immediately obvious what goes with what
approach.  If there's a specific question, let me know.  The one that
actually runs right now on the SAML 2 flow in the test bed is the lookup
one using the map, so 2A.

I think the work to implement any of these is largely done, at least in
the testbed.  We just need to pick one (or come up with another
solution).  Of the 2 fundamental approaches, I personally prefer the
second, lookup-based one (2A with the map, followed in preference by 2B
with URI->bean name translation).  I think the WebFlow transition stuff
could get messy (split across flow and bean definitions), and it also
means you have to maintain that in every flow definition potentially
(unless it's in an abstract one I guess). The Spring-aware lookup-based
stuff is all localized in one place in the Spring bean config, so just
one place to keep synchronized.

That's what I've got for now.

--Brent






-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://shibboleth.net/pipermail/dev/attachments/20140117/0c26e9f5/attachment.html 


More information about the dev mailing list