-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement idP resolution using OpenID Connect Discovery #13
Comments
Hi @binki. I remember that we talked in an IRC meeting about this. I think that the WebFinger lookup was used in one model, maybe that was an idea of @skorokithakis at that time? Currently and as far as I could see, https://github.com/letsauth/ladaemon uses the discovery URL, see https://github.com/letsauth/ladaemon/blob/master/src/oidc.rs#L42. But I think that's where the webfinger lookup could be added. |
I ended up finding a discussion of something similar in the ML archives after the fact. Thanks for pointing to the spot in the source, maybe I’ll find time to play with the daemon, but I’m not sure yet. |
So, I’ve started trying to write my own dummy idP since I don’t know off-hand of any example implementations. So far I have a faked out webfinger: https://client.webfinger.net/lookup?resource=ohnobinki%40turbo.coffee . We’ll see if I get any futher… ;-). |
(Pinging @rfk to get his blog post up on OpenID Connect and the quality of its dynamic registration spec...) |
Actually, I somehow missed the attachment on one of @rfk's responses in that mailing list thread. That's a very good place to start.
That's also my understanding. Without having actually implemented it, Webfinger does indeed look reasonable for discovery of a user's identity provider... but then we have to solve the problem of our daemon being able to talk to that provider without having been previously introduced and registered. Similarly, what protocol does the provider speak? How do we make that easy enough for individuals with their own domain to become their own identity providers? I don't have the headspace to tackle this right now, but I'd absolutely love it if someone (@binki, et al.) began exploring in this direction. It can be cleanly added to our list of auth strategies in the future, so it's not a blocker for v1.0, but we will need to solve this problem before we can claim to have lived up to our goal of empowering people to self-certify. |
So dynamic registration is one thing, but IIRC we wanted to try and keep the daemon stateless, right? And I assume most OIDC providers would not work well with trying to register the same callback URL a second time... |
Right. This is somewhere we likely need to develop a custom protocol, taking inspiration from Persona and OIDC Dynamic Registration and maintaining as much of OIDC as makes sense, without requiring true registration or long-term statefulness. |
Right now I’m slowly working through an implementation of the idP side of the specs as I have time. Hopefully the specs have some allowance for registration-free authentication, I think someone in that ML thread mentioned that implicit flow might allow that, but I haven’t gotten that far yet myself. Avoiding registration would also make the idP itself simpler. One thing I did want to note here is a decision I’ve made about the WebFinger lookup itself. The OpenID Connect Discovery 1.0 says:
However, the I’ve implemented an example of that at https://client.webfinger.net/lookup?resource=mailto%3Aohnobinki%40turbo.coffee where |
Sadly, I'm pretty sure the existing implicit flow does not allow this, mostly because it would be a security problem - you need some way to tell what redirect_uri values are legit for each client. I think we could invent a protocol that securely replaces "client registration" with "client discovery" along the lines of [1], but I'm not aware of any existing spec that avoids pre-registration of client credentials.
If you're happy to keep a bit of state in a cache to reduce overall server load, you might actually get away with this. IIUC the dynamic registration spec is fine with you registering the same client details multiple times, and re-registering is the recommended way to e.g. replace your client secret in the event of a data breach. [1] https://groups.google.com/d/msg/portier/kOc_SMY_9lI/DIuoD2HUBwAJ |
Even for the email link login to work you need state, right? Since it sounds like reregistering shouldn't be too big of a deal, caching the registration token for a few minutes at a time for the sake of staying with existing standards sounds like the way to go. |
Although TBH I'm not aware of any major OIDC IdP that actually implements the dynamic registration spec, so it may be a moot point. |
@binki You don't need state for the email login link, you can sign it using a secret so you just validate the signature when it comes back. |
The ladaemon however uses redis to store some state: https://github.com/portier/ladaemon/blob/master/src/store.rs. I think that's okay and would also be okay here. There is a difference between having some internal state used for making the authentication work and having state in the sense of users storing accounts and profil information. The line is where one ladeamon instance can't be swapped out with another without loosing stuff. |
Yeah, ladaemon has some state, but it's all short-lived. So if the database breaks down or whatever (or, if you want to setup your own instance), nothing is lost other than some limited performance penalty due to having to fetch more data in order to do the job. |
Has anyone looked at the proposals from ID4me? They want to solve discovery using a DNS TXT based solution. Might be interesting to add support for it on top of the WebFinger discovery. |
Hi @mhofman I hadn't looked at this yet. I see an incompatibility: We pretty much have baked into the project as a core assumption that the email address is the user identifier. I see it mentioned there as a possibility, but the main focus seems to be on URLs. And the Identity agent concept seems to resemble the role Mozilla Personas main instance played in the end, the part that made it a centralized service by accident. Is there a specific part of the spec at the discovery level that would be helpful for us? |
I believe they support any identifiers from the OpenID Connect spec, including email type "accounts". Maybe I'm getting this wrong, but wouldn't the Portier broker be able to act as a Relying Party, discover ID4me authorities using the DNS TXT Discovery system on top of the existing WebFinger Discovery for other OpenID Connect systems. The only thing I see as possibly being an issue is that ID4me basically mandates the usage of OpenID Connect Dynamic Client Registration, which means the broker would have to save the client_id / client_secret received the first time a new domain is encountered. This could probably be done in a sort dynamic configuration file? |
No, if I understand the spec correctly that would be possible. But what would we gain by that? Is there an email provider that has this set up? For enabling an authentication flow without having to check mails for custom domains we already have the webfinger detection, which works fine as far as I'm aware. Is id4me popular enough that it would help many users that already have this set up for their email domain?
Since the broker is supposed to be federated that might be a real issue though. So far we just don't do registration - it would only cause harm in our use case. |
WebFinger requires running an HTTP service that responds to the well-known URL on the anchor of the host part of the identifier. In the case of email identifiers that basically means the server at the apex of the domain! That is a major hindrance for most deployments. The idea behind ID4me (from what I gather, I'm not associated to the effort, just interested in the technology) is that by being able to point to any auth provider by simply changing DNS records, anyone owning a domain name can use a 3rd party of their choosing to handle their identity, similar to how they can choose any provider for their domain emails. It could be a service of the domain registrar, a service of the email provider (e.g. Google Apps accounts?), or an independent identity service (e.g. Auth0). Imagine if we required everyone needing emails on their domain to also run an based HTTP discovery service!
Google requires a client_id to be registered out of band. How is that provisioning done in the federated use case? Is it the same issue besides the dynamic nature of the registration? |
Okay, that I get! I don't understand completely yet how the DNS entry has to be formed to show the IdP of the email address given. But I see now how the broad protocol could work. That could work nicely and fit well, as an alternative scheme for when the email domain doesn't want to run a webserver at root level.
To activate sign in with google the broker has to be configured before, see the bottom https://github.com/portier/portier-broker#configuration, where a client_id is set. If it's only that it should be no issue, though I'm not sure that's actually still true when thinking about dynamic registration of multiple IdPs. Probably fine as well. Worst case it doesn't work with a different broker anymore, that's okay. I think I was mixing it up with the registration necessary in some OIDC authentication flows we considered for the flow between our RP and the portier broker. That's where we wanted to require no registration. |
The spec for the DNS TXT record is described in I-D.sanz-openid-dns-discovery. Basically it points the the host names to use for the identity authority and agent. More informations about the interactions between parties are in their technical overview.
Indeed, Portier broker would act as a Dynamic Registration client with the identity provider. Just to make sure I understand, is it expected that a shared Portier broker handle Google authentications? The configuration seem to indicate that a single client_id for Google can be configured, which means the shared Portier broker acts as a sort of "independent" client to Google OpenID Connect authentication, hiding the real Relying Party's identity. Couldn't this be ripe for abuse? In the case of a shared broker performing dynamic registration with identity providers, maybe the broker could retransmit the Relying Party's identity to avoid such issues. That would however mean storing the client secret based on the tuple (Relying Party server origin, identity provider), which can be argued is not simple configuration anymore, nor stateless. Again, all this isn't specific to ID4me, but to OpenID Connect Discovery and the Dynamic Registration supposedly necessary for it. |
When it comes to philosophical differences between Portier and ID4me, you're right, there might be some mismatch with what is considered the identity handle. The authority only provides a stable opaque handle identifying the authorized user. That handle can be specific to the Relying Party that asked to authenticate the user. Technically multiple identifiers (emails, urls, etc.) can be linked to the same identity. The email identifier shouldn't be used as a stable handle. The reason is that if the domain expires and gets re-registered, the new owner would be able to steal the identity. Personal motivationI personally have a beef with most websites that insist on learning my primary email backing my Google account, which is why I'm interested in better authentication schemes. When I tested Portier with an email in the form of `[email protected]`, portier ended up showing I was logged in as `[email protected]`, which I then learned is by design. What I'll probably end up doing is build a custom identity provider that returns an email specific to the relying party's origin, the same way as I do nowadays manually with my email aliases on my domain. |
Well, design. It is by design, but it actually caused enough issues that we though about reverting it back, at least to only the normalization portier is doing. See portier/portier-broker#165. Though that's more about the . in the address, less about the +, that portier would so far remove as well, with the current code. But it's the same issue. Like @stephank wrote:
I assume you'd agree with that change. I do as well, but it would mean quite some work for me making sure users of my services using portier don't get locked out of their account.
No, the new owner just would be the new owner of the identity. That's unavoidable imho. The only way around that is adding meatspace authentication factors, 2-factor or passwords again, bound to the service or broker itself. Binding it to the broker would require state and destroy the federalization, so that's no option. A site wanting to change what is an identity - which is who controls the email address right now - would need to introduce 2FA on its own. If wanting to address that concern, Portier should be extended to support that in its auth flow - the RP providing the second factor, Portier doing the rest of the work.
Thanks for the links. So the DNS of the email domain would have an entry for the email address, the |
The concept of idPs resolved via email addresses (instead of OpenID discovery URIs) is my favorite feature of Persona. It made Persona much easier to use than traditional OpenID where a website either only permits the user to select from a list of trusted OpenID providers or the user has to paste in a “discovery URI”. Persona used the authority information inherent in the user’s identity (email), the domain name, as the starting point for idP discovery. Analogous to how an MTA looks up
MX
records, Persona checked for well-known DNS records to see if the mail provider defined an idP. If the mail provider did provide an idP, the user would get a much nicer login experience.Based on how letsauth is right now implementing OpenID Connect and how it seems like a standard which will get wide adoption, perhaps letsauth could set a goal to define an idP lookup mechanism similar to Persona. Or maybe OpenID Connect already defines a way to do this…
At http://openid.net/connect/ , I see Discovery and Dynamic Registration. So perhaps Discovery defines a way to find what OpenID Connect provider should be used for an email address. Right in the spec is a description of how to form a WebFinger lookup for a typed email address. Given email
[email protected]
, you would send a request tohttps://example.org/.well-known/webfinger?resource=acct%3auser%40example.org&rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer
. If the idP implements this optional endpoint, the request should yield enough information to find the OpenID Connect idP for the user.Of course, this is only the first step of a many step process and there are other points where failure could happen. I think maybe letsauth would have to use Dynamic Client Registration and keep track of its registrations with providers, etc. But at a glance it appears that decentralized idP lookup based on email address is already defined by a well-accepted standard and the standard which letsauth is using as a basis for its own protocol, nonetheless.
Of course, such a mechanism can’t replace letsauth. For email addresses for which OpenID Connect providers cannot be discovered, the email hash login would provide a baseline login experience. And a letsauth relier can be kept clean and simple if it can always delegate to letsauth rather than implementing the discovery itself.
The text was updated successfully, but these errors were encountered: