diff --git a/Gemfile b/Gemfile index 26b0403a..ecccfab9 100644 --- a/Gemfile +++ b/Gemfile @@ -27,7 +27,7 @@ gem 'devise', '~> 4.9', '>= 4.9.2' gem 'devise-encryptable', '~> 0.2.0' gem 'omniauth', '~> 2.1' gem 'omniauth-rails_csrf_protection', '~> 1.0' -gem 'omniauth-oauth2', '~> 1.8' +gem "omniauth_openid_connect", "~> 0.7.1" # For pagination UI. gem 'will_paginate', '~> 4.0' diff --git a/Gemfile.lock b/Gemfile.lock index d369969f..7b90a521 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -83,6 +83,7 @@ GEM tzinfo (~> 2.0) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) + aes_key_wrap (1.1.0) async (2.8.1) console (~> 1.10) fiber-annotation @@ -105,6 +106,7 @@ GEM async async-pool (0.4.0) async (>= 1.25) + attr_required (1.0.2) babel-source (5.8.35) babel-transpiler (0.7.0) babel-source (>= 4.0, < 6) @@ -112,6 +114,7 @@ GEM base64 (0.2.0) bcrypt (3.1.20) bigdecimal (3.1.6) + bindata (2.5.0) bindex (0.8.1) bootsnap (1.18.3) msgpack (~> 1.2) @@ -140,6 +143,8 @@ GEM drb (2.2.0) ruby2_keywords e2mmap (0.1.0) + email_validator (2.2.4) + activemodel erubi (1.12.0) execjs (2.9.1) falcon (0.43.0) @@ -157,6 +162,8 @@ GEM samovar (~> 2.1) faraday (2.9.0) faraday-net_http (>= 2.0, < 3.2) + faraday-follow_redirects (0.3.0) + faraday (>= 1, < 3) faraday-net_http (3.1.0) net-http ffi (1.16.3) @@ -183,8 +190,13 @@ GEM jsbundling-rails (1.3.0) railties (>= 6.0.0) json (2.7.1) - jwt (2.8.1) + json-jwt (1.16.6) + activesupport (>= 4.2) + aes_key_wrap base64 + bindata + faraday (~> 2.0) + faraday-follow_redirects launchy (2.5.2) addressable (~> 2.8) letter_opener (1.9.0) @@ -223,23 +235,29 @@ GEM nokogiri (1.16.2) mini_portile2 (~> 2.8.2) racc (~> 1.4) - oauth2 (2.0.9) - faraday (>= 0.17.3, < 3.0) - jwt (>= 1.0, < 3.0) - multi_xml (~> 0.5) - rack (>= 1.2, < 4) - snaky_hash (~> 2.0) - version_gem (~> 1.1) omniauth (2.1.2) hashie (>= 3.4.6) rack (>= 2.2.3) rack-protection - omniauth-oauth2 (1.8.0) - oauth2 (>= 1.4, < 3) - omniauth (~> 2.0) omniauth-rails_csrf_protection (1.0.1) actionpack (>= 4.2) omniauth (~> 2.0) + omniauth_openid_connect (0.7.1) + omniauth (>= 1.9, < 3) + openid_connect (~> 2.2) + openid_connect (2.3.0) + activemodel + attr_required (>= 1.0.0) + email_validator + faraday (~> 2.0) + faraday-follow_redirects + json-jwt (>= 1.16) + mail + rack-oauth2 (~> 2.2) + swd (~> 2.0) + tzinfo + validate_url + webfinger (~> 2.0) openssl (3.2.0) orm_adapter (0.5.0) parallel (1.24.0) @@ -265,6 +283,13 @@ GEM rack (>= 1.0, < 4) rack-mini-profiler (3.3.1) rack (>= 1.2.0) + rack-oauth2 (2.2.1) + activesupport + attr_required + faraday (~> 2.0) + faraday-follow_redirects + json-jwt (>= 1.11.0) + rack (>= 2.1.0) rack-protection (4.0.0) base64 (>= 0.1.0) rack (>= 3.0.0, < 4) @@ -349,9 +374,6 @@ GEM shell (0.8.1) e2mmap sync - snaky_hash (2.0.1) - hashie - version_gem (~> 1.1, >= 1.1.1) sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) @@ -363,6 +385,11 @@ GEM mini_portile2 (~> 2.8.0) stackprof (0.2.26) stringio (3.1.0) + swd (2.0.3) + activesupport (>= 3) + attr_required (>= 0.0.5) + faraday (~> 2.0) + faraday-follow_redirects sync (0.5.0) temple (0.10.3) terser (1.2.0) @@ -380,7 +407,9 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) uri (0.13.0) - version_gem (1.1.3) + validate_url (1.0.15) + activemodel (>= 3.0.0) + public_suffix warden (1.2.9) rack (>= 2.0.9) web-console (4.2.1) @@ -388,6 +417,10 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + webfinger (2.1.3) + activesupport + faraday (~> 2.0) + faraday-follow_redirects webrick (1.8.1) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) @@ -417,8 +450,8 @@ DEPENDENCIES mysql2 (~> 0.5.5) nokogiri (~> 1.15, >= 1.15.3) omniauth (~> 2.1) - omniauth-oauth2 (~> 1.8) omniauth-rails_csrf_protection (~> 1.0) + omniauth_openid_connect (~> 0.7.1) parallel (~> 1.23) rack-attack (~> 6.7) rack-mini-profiler (~> 3.1) diff --git a/bin/neopass-server b/bin/neopass-server index 283dbffd..358da822 100755 --- a/bin/neopass-server +++ b/bin/neopass-server @@ -3,14 +3,14 @@ * A test NeoPass server! This is a very lean, hacky implementation, designed * to just see the basic OAuth interactions Work At All. * - * First, we have a "backing server", which is a `oauth2-mock-server` instance - * that's easy to spin up and have perform OAuth for us. We give it a hardcoded - * development-only key, and it just auto-grants permissions! + * This server is an `oauth2-mock-server` instance that's easy to spin up and + * have perform OAuth for us. We give it a hardcoded development-only key, and + * it just auto-grants permissions! * - * We also have a "main server", which obeys the actual NeoPass API: the - * backing server isn't configurable with stuff like paths, so we use the main - * server to proxy from the paths in the NeoPass spec to the paths the backing - * server uses. + * It slightly differs from the NeoPass spec, in that it uses different paths + * for its endpoints, but that's okay: DTI will use OpenID's "discovery" + * feature to discover those endpoints via a single well-known path, without + * needing them hardcoded. */ const fs = require("node:fs/promises"); @@ -67,7 +67,7 @@ async function ensureCertsExist() { } } -async function startBackingServer(port) { +async function startServer(port) { const server = new OAuth2Server( keyPath, certPath, @@ -90,53 +90,12 @@ async function startBackingServer(port) { }); await server.start(port, "localhost"); - console.log(`Started NeoPass backing server at: ${server.issuer.url}`); -} - -async function startMainServer(port) { - const fetch = (await import("node-fetch")).default; - - const app = express(); - app.use(express.text({ type: "*/*" })); - - app.get("/", (req, res) => res.end("NeoPass development server for DTI!")); - - app.get("/oauth2/auth", (req, res) => { - const query = urlLib.parse(req.url).query; - res.redirect(`http://localhost:8686/authorize?${query}`); - }); - - app.post("/oauth2/token", async (req, res) => { - try { - // For POST requests, the HTTP spec doesn't allow a redirect to a - // POST, so we proxy the request instead. - const backingRes = await fetch("http://localhost:8686/token", { - method: "POST", - headers: { - "Content-Type": req.get("Content-Type"), - }, - body: req.body, - }); - if (!backingRes.ok) { - throw new Error(`backing server returned status ${res.status}`); - } - - res.set("Content-Type", backingRes.headers.get("Content-Type")); - return res.end(await backingRes.text()); - } catch (error) { - console.error(error); - return res.end(error.message); - } - }); - - await new Promise((resolve) => app.listen(port, resolve)); - console.log(`Started NeoPass main server at: http://localhost:${port}`); + console.log(`Started NeoPass development server at: ${server.issuer.url}`); } async function main() { await ensureCertsExist(); - await startBackingServer(8686); - await startMainServer(8585); + await startServer(8585); } main().catch((error) => { diff --git a/config/environments/development.rb b/config/environments/development.rb index 59545ee8..c8336b21 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -121,5 +121,9 @@ Rails.application.configure do config.neopass_access_secret = "1" # Use the local NeoPass development server. - config.neopass_origin = "http://localhost:8585" + config.neopass_origin = "https://localhost:8585" + + # Set the NeoPass redirect callback URL. + config.neopass_redirect_uri = + "http://localhost:3000/auth_users/auth/neopass/callback" end diff --git a/config/environments/production.rb b/config/environments/production.rb index eb8dc9ca..6be22103 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -140,4 +140,8 @@ Rails.application.configure do # Use the live NeoPass production server. config.neopass_origin = "https://oidc.neopets.com" + + # Set the NeoPass redirect callback URL. + config.neopass_redirect_uri = + "https://impress.openneo.net/auth_users/auth/neopass/callback" end diff --git a/config/environments/test.rb b/config/environments/test.rb index c43da225..79dd5eee 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -76,5 +76,9 @@ Rails.application.configure do config.neopass_access_secret = "1" # Use the local NeoPass development server. - config.neopass_origin = "http://localhost:8585" + config.neopass_origin = "https://localhost:8585" + + # Set the NeoPass redirect callback URL. + config.neopass_redirect_uri = + "http://localhost:3000/auth_users/auth/neopass/callback" end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 19378677..a39ee956 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true -require "strategies/neopass" # Assuming you have not yet modified this file, each configuration option below # is set to its default value. Note that some are commented out while others @@ -274,7 +273,21 @@ Devise.setup do |config| # ==> OmniAuth # Add a new OmniAuth provider. Check the wiki for more information on setting # up on your models and hooks. - config.omniauth :neopass, strategy_class: Strategies::NeoPass + config.omniauth :openid_connect, { + name: :neopass, + scope: [:openid, :email, :profile], + response_type: :code, + issuer: Rails.configuration.neopass_origin, + discovery: true, + client_options: { + identifier: "DTI-TODO", + secret: "DTI-TODO", + redirect_uri: Rails.configuration.neopass_redirect_uri, + }, + } + + # Output OmniAuth debug info to the server logs in development + OmniAuth.config.logger = Rails.logger if Rails.env.development? # ==> Warden configuration # If you want to use other strategies, that are not supported by Devise, or diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 0be78463..620da4d8 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -18,7 +18,4 @@ ActiveSupport::Inflector.inflections(:en) do |inflect| # Teach Zeitwerk that `RocketAMF` is what to expect in `lib/rocketamf`. inflect.acronym "RocketAMF" - - # Teach Zeitwerk that "NeoPass" is what to expect in `neopass.rb`. - inflect.acronym "NeoPass" end diff --git a/lib/strategies/neopass.rb b/lib/strategies/neopass.rb deleted file mode 100644 index 91cebfbc..00000000 --- a/lib/strategies/neopass.rb +++ /dev/null @@ -1,13 +0,0 @@ -require "omniauth-oauth2" - -module Strategies - class NeoPass < OmniAuth::Strategies::OAuth2 - option :name, "neopass" - - option :client_options, { - site: Rails.configuration.neopass_origin, - authorize_url: "/oauth2/auth", - token_url: "/oauth2/token", - } - end -end diff --git a/vendor/cache/aes_key_wrap-1.1.0.gem b/vendor/cache/aes_key_wrap-1.1.0.gem new file mode 100644 index 00000000..1a4d2253 Binary files /dev/null and b/vendor/cache/aes_key_wrap-1.1.0.gem differ diff --git a/vendor/cache/attr_required-1.0.2.gem b/vendor/cache/attr_required-1.0.2.gem new file mode 100644 index 00000000..abd0ba72 Binary files /dev/null and b/vendor/cache/attr_required-1.0.2.gem differ diff --git a/vendor/cache/bindata-2.5.0.gem b/vendor/cache/bindata-2.5.0.gem new file mode 100644 index 00000000..ea366531 Binary files /dev/null and b/vendor/cache/bindata-2.5.0.gem differ diff --git a/vendor/cache/email_validator-2.2.4.gem b/vendor/cache/email_validator-2.2.4.gem new file mode 100644 index 00000000..8c4df6c3 Binary files /dev/null and b/vendor/cache/email_validator-2.2.4.gem differ diff --git a/vendor/cache/faraday-follow_redirects-0.3.0.gem b/vendor/cache/faraday-follow_redirects-0.3.0.gem new file mode 100644 index 00000000..edb1d77d Binary files /dev/null and b/vendor/cache/faraday-follow_redirects-0.3.0.gem differ diff --git a/vendor/cache/json-jwt-1.16.6.gem b/vendor/cache/json-jwt-1.16.6.gem new file mode 100644 index 00000000..fe2da9a3 Binary files /dev/null and b/vendor/cache/json-jwt-1.16.6.gem differ diff --git a/vendor/cache/jwt-2.8.1.gem b/vendor/cache/jwt-2.8.1.gem deleted file mode 100644 index e41a6cd6..00000000 Binary files a/vendor/cache/jwt-2.8.1.gem and /dev/null differ diff --git a/vendor/cache/oauth2-2.0.9.gem b/vendor/cache/oauth2-2.0.9.gem deleted file mode 100644 index f875e11d..00000000 Binary files a/vendor/cache/oauth2-2.0.9.gem and /dev/null differ diff --git a/vendor/cache/omniauth-oauth2-1.8.0.gem b/vendor/cache/omniauth-oauth2-1.8.0.gem deleted file mode 100644 index 3e58a53b..00000000 Binary files a/vendor/cache/omniauth-oauth2-1.8.0.gem and /dev/null differ diff --git a/vendor/cache/omniauth_openid_connect-0.7.1.gem b/vendor/cache/omniauth_openid_connect-0.7.1.gem new file mode 100644 index 00000000..0302c81e Binary files /dev/null and b/vendor/cache/omniauth_openid_connect-0.7.1.gem differ diff --git a/vendor/cache/openid_connect-2.3.0.gem b/vendor/cache/openid_connect-2.3.0.gem new file mode 100644 index 00000000..95e2de95 Binary files /dev/null and b/vendor/cache/openid_connect-2.3.0.gem differ diff --git a/vendor/cache/rack-oauth2-2.2.1.gem b/vendor/cache/rack-oauth2-2.2.1.gem new file mode 100644 index 00000000..801e615d Binary files /dev/null and b/vendor/cache/rack-oauth2-2.2.1.gem differ diff --git a/vendor/cache/snaky_hash-2.0.1.gem b/vendor/cache/snaky_hash-2.0.1.gem deleted file mode 100644 index 7f75a853..00000000 Binary files a/vendor/cache/snaky_hash-2.0.1.gem and /dev/null differ diff --git a/vendor/cache/swd-2.0.3.gem b/vendor/cache/swd-2.0.3.gem new file mode 100644 index 00000000..bd42eec8 Binary files /dev/null and b/vendor/cache/swd-2.0.3.gem differ diff --git a/vendor/cache/validate_url-1.0.15.gem b/vendor/cache/validate_url-1.0.15.gem new file mode 100644 index 00000000..fe2932f8 Binary files /dev/null and b/vendor/cache/validate_url-1.0.15.gem differ diff --git a/vendor/cache/version_gem-1.1.3.gem b/vendor/cache/version_gem-1.1.3.gem deleted file mode 100644 index d11edfb4..00000000 Binary files a/vendor/cache/version_gem-1.1.3.gem and /dev/null differ diff --git a/vendor/cache/webfinger-2.1.3.gem b/vendor/cache/webfinger-2.1.3.gem new file mode 100644 index 00000000..fab9ff46 Binary files /dev/null and b/vendor/cache/webfinger-2.1.3.gem differ