Skip to content
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

Complete rewrite of the library #50

Merged
merged 32 commits into from
May 8, 2023
Merged

Complete rewrite of the library #50

merged 32 commits into from
May 8, 2023

Conversation

AndrewDryga
Copy link
Collaborator

@AndrewDryga AndrewDryga commented Apr 21, 2023

This PR addresses several issues we faced while using the official version:

  1. We have a product where each client can define a list of their OIDC providers, meaning there may be thousands of them and a single GenServer holding the state becomes a bottleneck with a large state;
  2. The provider name was an atom which also means somebody can overload our atom table by keep creating new OIDC configs;
  3. There is no need to restart the library every time the config is updated anymore;
  4. The tests are rewritten to avoid using mocks because the actual production code was not covered sufficiently;
  5. The HTTP client is replaced using Finch/Mint, reducing the number of dependencies for a typical Phoenix project and adding telemetry metrics for HTTP requests;
  6. Add support for end_session_endpoint #45, Support for userinfo endpoint #39, Validate OpenID claims #36 are either re-implemented or manually merged.

I know this is a lot to review, it has breaking changes (hence the major version bump), but this code is battle tested at https://github.com/firezone/firezone on thousands of instances.

This also resolves most of the PR's and issues opened, I went through them and made a list so that once PR is merged they are closed automatically:
Closes #45
Closes #39
Closes #36
Closes #49
Closes #44
Closes #42
Closes #37
Closes #28
Closes #40
Closes #35
Closes #31
Closes #29
Closes #24

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
@bcardarella
Copy link
Member

@AndrewDryga thank you, there is a lot to review but I don't think this is in a state to review yet. There are references to Firezone and modules that don't exist. Can you please restore the references to DockYard, remove the references to Firezone? As I noted adding Firezone as a collaborator makes sense but not some of the changes as they're here

@AndrewDryga
Copy link
Collaborator Author

@bcardarella I reverted all the changes and updated README.md to reflect new function interfaces.

jamilbk and others added 22 commits April 21, 2023 11:43
The library was storing a state in a GenServer which is causing various issues:
1. When configuration is changed we needed to restart the process having a small OIDC downtime during the process;
2. There were no way to run async tests because GenServer was querying discovery document URL's on the background, which means we wasn't able to use Bypass in integration tests
3. Storing a lot of configuration on the library side would cause a lot of issues once we have multi-tenancy and a ton of different configuration, the GenServer will be a bottleneck.
@bcardarella
Copy link
Member

@AndrewDryga awesome, thanks! @xn can we try this branch out on dockyard admin and confirm? I'll also do a code review

mix.exs Outdated Show resolved Hide resolved
mix.exs Outdated Show resolved Hide resolved
@bcardarella
Copy link
Member

@AndrewDryga I think you've addressed all of the code review issues. I want to wait on our own internal test of this branch replacing the previous version of the lib before merging. Thanks!

@AndrewDryga AndrewDryga changed the title Complete rewrite of a library Complete rewrite of the library Apr 21, 2023
@@ -120,14 +98,17 @@ get("/session/authorization-uri", SessionController, :authorization_uri)
# session_controller.ex
# you could also take the `provider` as a query param to pass into the function
def authorization_uri(conn, _params) do
json(conn, %{uri: OpenIDConnect.authorization_uri(:google)})
google_config = Application.fetch_env!(:my_app, :google_oidc_config)
json(conn, %{uri: OpenIDConnect.authorization_uri(google_config)})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authorization_uri/1 returns an :ok tuple.

We want something like:

def authorization_uri(conn, _params) do
  google_config = Application.fetch_env!(:my_app, :google_oidc_config)
  {:ok, uri} = OpenIDConnect.authorization_uri(google_config)
  
  json(conn, %{uri: uri})
end

@xn
Copy link
Contributor

xn commented Apr 26, 2023

@AndrewDryga This is great stuff! Really appreciate the work!

One small documentation fix and it looks good to me.

@bcardarella
Copy link
Member

@AndrewDryga if you can make the requested documentation change ☝️ we can get this merged

@xn xn self-requested a review May 8, 2023 20:23
@xn xn merged commit f39c60b into DockYard:master May 8, 2023
@AndrewDryga
Copy link
Collaborator Author

Ah sorry guys, I did not notice the notification about that doc change comment. Thank you! Glad to see it merged.

@AndrewDryga
Copy link
Collaborator Author

Should I open a different PR for the doc change?

@xn
Copy link
Contributor

xn commented May 8, 2023

No worries, I just opened #51

@xn
Copy link
Contributor

xn commented May 8, 2023

Thank you so much for all of your hard and excellent work!

@bcardarella
Copy link
Member

@AndrewDryga no worries, thank you for the PR 🎉


defp build_document(document_json) do
keys = Map.keys(document_json)
required_keys = ["jwks_uri", "authorization_endpoint", "token_endpoint"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit late to the party but should this also include "userinfo_endpoint" given that it uses Map.fetch! on this key as well? OR should it not use fetch! given that it doesn't seem to be required by the RFC? 🤔

token_endpoint: Map.fetch!(document_json, "token_endpoint"),
userinfo_endpoint: Map.fetch!(document_json, "userinfo_endpoint"),
response_types_supported:
Map.get(document_json, "response_types_supported")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also should this default to []? Map.get(document_json, "response_types_supported", []). Otherwise if it's nil it will fail on Enum.map I think? 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants