On 12/06/2016 01:17, Dirkjan Ochtman wrote:
>
> Gap 1: it seems like a secure implementation of OpenID Connect
> requires a pre-shared secret between the relying party and the
> identity provider. This establishes a relationship between these two,
> which means a true OpenID Connect IdP can never send an Identity Token
> to a random host pointed to by some web form. Currently, it's
> trivially possible to have an Identity Token for some user be sent
> from LA to a random, different host than the user might think, which
> seems bad to me.
I don't believe a secret is required in order to ensure security,
although it does make it easier to get the security right.
IIUC the security of the secret-free OIDC "implicit flow" depends
crucially on knowing what redirect_uri values can be used with what
client_id values, and on having both sides of the dance check this
correspondence.
You start the OIDC login by specifying a client_id and redirect_uri, and
it's up to the provider to check that the (client_id, redirect_uri) pair
is valid.
You end the OIDC login by having the user land on the specified
redirect_uri, with an id_token that's scoped to a particular client_id.
At this point the relier must also check that the (client_id,
redirect_uri) pair is valid, i.e. that they represent values for this
relier and not someone else.
What does it mean for a (client_id, redirect_uri) pair to be valid? Well...
> Gap 2: what do we do for "native" LA identity providers? One simple
> solution would be to use OpenID Connect for that case, too. The
> reliance of OIDC on pre-shared secrets however makes this less
> attractive if we want to support identity providers without central
> registration. While it's okay to maintain a list of secrets and client
> identifiers for a handful of famous IdPs (the Rust implementation can
> read these from a configuration file), I think we'd like to allow any
> domain to be an IdP, and the requirement to have pre-shared secrets
> makes it annoying to scale this up.
I strongly agree that pre-registration is something to be avoided, and
I'm hopeful we can find a way to make it work.
OpenID Connect has a standard that's designed to solve this problem, the
"dynamic client registration" spec:
http://openid.net/specs/openid-connect-registration-1_0.html
It's been a while since I read it in detail, but I remember having two
broad take-aways from it:
1) The data-model and security-model is pretty good.
2) The way it portions out work between reliers and IdPs creates
weak incentives for either side to actually implement it.
This spec basically provides an API for each relier to register itself
with one or more IdPs. Automating that registration is good, but
getting rid of it entirely would be even better.
What I think would work well, is if we took the data model from this
spec and combined it with the idea of discovery ala persona.
Some quick thoughts about a half-baked proposal:
* Identify clients by URL. IIUC the current protocol and prototype does
this already. But the key point is that it's a full URL, including
path component, not just an origin.
* Rather than requiring reliers to register themselves to the IdP,
have the IdP discover public metadata about each relier by looking
up a support document.
It could work like this:
1) The relier starts the flow by hitting the LA authentication endpoint
like it does now:
POST /auth HTTP/1.1
login_hint=
m...@example.com&
scope=openid%20email&
response_type=id_token&
client_id=
https://rp.info/&
redirect_uri=
https://rp.info/login
2) The IdP requests the OpenID configuration document from the relier,
in order to find its metadata as specced at [1]:
GET
https://rp.info/.well-known/openid-configuration
3) The IdP validates that the redirect_uri is one that's listed in the
discovered metadata, along with a bunch of other security checking
rules.
4) The flow proceeds from here as specified in the current LA protocol.
N) At the end of all this, the relier must check that it has received
an id_token that's propery scoped to its client_id URL.
I think this would give us the same level of security as the existing
OIDC client registration spec, while allowing clients to come into
existing merely by publishing something at a URL, rather than
registering for a shared secret.
Two interesting things that could come out of this:
* The same protocol could be used between the relier and "native" LA
IdPs. The native IdP could follow all the same discovery steps as
the LA daemon, and the relier doesn't have to do anything at all
in order to be compatible with it.
* We could probably define a sensible default suite of metadata for
reliers that don't publish a full OpenID configuration. Among
other things, it would restrict the allowed value of redirect_uri
to precisely match the client_id.
I'm about to go jump on a plane, but I'll see if I can use the flight
time to flesh out the details here a little more and post a concrete
protocol proposal...
[1]
http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
> Gap 3: as noted in the protocol write-up I did, we don't yet have an
> established path of returning errors to the RP. Right now, the demo-RP
> that Dan worked on [4] and that I have been testing on pretty much
> only supports the "happy path". I think isn't so hard, but we do need
> consensus here.
One thing to be careful of here is open redirects. The OAuth2 spec
essentially says that you should handle errors by redirecting back to
the client's redirect_uri with URL params describing the error.
Combined with dynamic regisreation/discovering or redirect uris this is
pretty much a spec-mandated open redirect vulnerability :-/
Cheers,
Ryan