diff --git a/.env.development b/.env.development index 85e81807e2..910785e85c 100644 --- a/.env.development +++ b/.env.development @@ -30,3 +30,6 @@ OIDC_SECRET_KEY=oidc-development-secret PAYPAL_BASE_URL=https://api-m.sandbox.paypal.com WCA_REGISTRATIONS_URL=http://localhost:8000 WCA_REGISTRATIONS_BACKEND_URL=http://wca_registration_handler:3000 +STAGING_OAUTH_URL=https://staging.worldcubeassociation.org +STAGING_OAUTH_CLIENT=example-application-id +STAGING_OAUTH_SECRET=example-secret diff --git a/.env.test b/.env.test index dd3ee973cf..1fa573efcf 100644 --- a/.env.test +++ b/.env.test @@ -29,3 +29,6 @@ PAYPAL_CLIENT_SECRET=EIknLp919Gbuj2CYmEWECyKH5HwJTWQNuqFuCr1qFMrGNzwkF8dD0VkwzwI PAYPAL_ATTRIBUTION_CODE=FLAVORsb-noyt529176316_MP PAYPAL_BASE_URL=https://api-m.sandbox.paypal.com WCA_REGISTRATIONS_BACKEND_URL=http://wca_registration_handler:3000 +STAGING_OAUTH_URL=https://staging.worldcubeassociation.org +STAGING_OAUTH_CLIENT=example-application-id +STAGING_OAUTH_SECRET=example-secret diff --git a/app/assets/stylesheets/wca.scss b/app/assets/stylesheets/wca.scss index 39b885a534..3055c308ce 100644 --- a/app/assets/stylesheets/wca.scss +++ b/app/assets/stylesheets/wca.scss @@ -2,6 +2,10 @@ font-family: monospace; } +.watermark { + background-image: url("data:image/svg+xml;utf8,WCA Testing Site"); +} + table.table { // From http://stackoverflow.com/a/10688485 &.table-nonfluid { diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 967a6c9e1e..e5b6f9c162 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -8,6 +8,43 @@ class SessionsController < Devise::SessionsController # Make sure this happens always before any before_action protect_from_forgery with: :exception, prepend: true + def staging_oauth_login + return if EnvConfig.WCA_LIVE_SITE? + + client = OAuth2::Client.new(AppSecrets.STAGING_OAUTH_CLIENT, AppSecrets.STAGING_OAUTH_SECRET, + site: EnvConfig.STAGING_OAUTH_URL) + redirect_uri = staging_login_url + + unless params[:code].present? + return redirect_to client.auth_code.authorize_url( + redirect_uri: redirect_uri, + ), allow_other_host: true + end + + access_token = client.auth_code.get_token( + params[:code], redirect_uri: redirect_uri + ).token + + # Get /me to figure out which user we are + connection = Faraday.new( + url: EnvConfig.STAGING_OAUTH_URL, + headers: { + 'Authorization' => "Bearer #{access_token}", + 'Content-Type' => 'application/json', + }, + ) + + results = connection.get("/api/v0/me").body + + user = User.find(results["me"]["id"]) + if user + sign_in(user) + redirect_to root_url, notice: "Successfully logged in as #{user.wca_id}" + else + redirect_to root_url, alert: "Your user is not yet imported into our Staging Website, please try again later" + end + end + def new super # Remove any lingering user data from previous login attempt diff --git a/app/views/devise/sessions/_live_login.html.erb b/app/views/devise/sessions/_live_login.html.erb new file mode 100644 index 0000000000..df3def63a1 --- /dev/null +++ b/app/views/devise/sessions/_live_login.html.erb @@ -0,0 +1,9 @@ +
+
+

<%= t('devise.sessions.new.sign_in') %>

+
+ +
+ <%= render 'password_form' %> +
+
diff --git a/app/views/devise/sessions/_password_form.html.erb b/app/views/devise/sessions/_password_form.html.erb new file mode 100644 index 0000000000..6fcf2dd409 --- /dev/null +++ b/app/views/devise/sessions/_password_form.html.erb @@ -0,0 +1,33 @@ +<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { role: "form" }) do |f| %> +
+ <%= f.label :login %> + <%= f.text_field :login, autofocus: false, class: "form-control", tabindex: "1" %> +
+
+ <%= f.label :password %> + <%= link_to t("devise.passwords.new.forgot_your_password"), new_user_password_path %>
+ <%= f.password_field :password, autocomplete: "off", class: "form-control", tabindex: "2" %> + <% if ServerSetting.exists?(DatabaseDumper::DEV_TIMESTAMP_NAME) %> +

+ Hint! It looks like you are using the + developer export + <% unless DbDumpHelper.use_staging_password? %> + , every user's password is "wca" + <% end %> + . You can find email addresses to log in with over on + <%= link_to "the delegates page", delegates_path %>. +

+ <% end %> +
+ <% if devise_mapping.rememberable? %> +
+ +
+ <% end %> + <%= f.submit t('devise.sessions.new.sign_in'), class: "btn btn-primary", tabindex: "3" %> + <%= t 'wca.devise.no_account' %> <%= link_to t('devise.shared.links.sign_up'), new_user_registration_path %>! +<% end %> + diff --git a/app/views/devise/sessions/_staging_login.html.erb b/app/views/devise/sessions/_staging_login.html.erb new file mode 100644 index 0000000000..1fb4b3710d --- /dev/null +++ b/app/views/devise/sessions/_staging_login.html.erb @@ -0,0 +1,25 @@ +
+
+

Recommended: Automatic Sign In

+
+
+
+ +
+
+
+ +
+ + +
+
+ <%= render 'password_form' %> +
+
+
+ diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 7ef06c6106..d7e8274354 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -3,44 +3,10 @@ <% # i18n-tasks-use t('devise.failure.not_found_in_database') %> <% # i18n-tasks-use t('devise.failure.unconfirmed') %> <%= render layout: "devise/conversion_message", locals: { user: resource } do %> -
-
-

<%= t('devise.sessions.new.sign_in') %>

-
-
- <%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { role: "form" }) do |f| %> -
- <%= f.label :login %> - <%= f.text_field :login, autofocus: true, class: "form-control", tabindex: "1" %> -
-
- <%= f.label :password %> - <%= link_to t("devise.passwords.new.forgot_your_password"), new_user_password_path %>
- <%= f.password_field :password, autocomplete: "off", class: "form-control", tabindex: "2" %> - <% if ServerSetting.exists?(DatabaseDumper::DEV_TIMESTAMP_NAME) %> -

- Hint! It looks like you are using the - developer export - <% unless DbDumpHelper.use_staging_password? %> - , every user's password is "wca" - <% end %> - . You can find email addresses to log in with over on - <%= link_to "the delegates page", delegates_path %>. -

- <% end %> -
- <% if devise_mapping.rememberable? %> -
- -
- <% end %> - <%= f.submit t('devise.sessions.new.sign_in'), class: "btn btn-primary", tabindex: "3" %> - <%= t 'wca.devise.no_account' %> <%= link_to t('devise.shared.links.sign_up'), new_user_registration_path %>! - <% end %> -
-
+ <% if Rails.env.production? && !EnvConfig.WCA_LIVE_SITE? %> + <%= render 'staging_login' %> + <% else %> + <%= render 'live_login' %> + <% end %> <% end %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index f81da3b26d..24e41ddea4 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -90,7 +90,7 @@ <% end %> - +"> <% hide_wca_navbars = yield(:hide_wca_navbars).present? %> <% if !hide_wca_navbars %> diff --git a/app_secrets.rb b/app_secrets.rb index 2b366213f1..b982fa6518 100644 --- a/app_secrets.rb +++ b/app_secrets.rb @@ -80,6 +80,12 @@ def vault_file(secret_name, file_path, refresh: true) vault :OIDC_SECRET_KEY vault :SLACK_WST_BOT_TOKEN vault :TNOODLE_PUBLIC_KEY + + # To allow logging in to staging with your prod account + unless EnvConfig.WCA_LIVE_SITE? + vault :STAGING_OAUTH_CLIENT + vault :STAGING_OAUTH_SECRET + end else mandatory :DATABASE_PASSWORD, :string mandatory :GOOGLE_MAPS_API_KEY, :string @@ -96,6 +102,8 @@ def vault_file(secret_name, file_path, refresh: true) mandatory :STRIPE_PUBLISHABLE_KEY, :string mandatory :JWT_KEY, :string mandatory :OIDC_SECRET_KEY, :string + mandatory :STAGING_OAUTH_CLIENT, :string + mandatory :STAGING_OAUTH_SECRET, :string optional :AWS_ACCESS_KEY_ID, :string, '' optional :AWS_SECRET_ACCESS_KEY, :string, '' diff --git a/config/initializers/faraday_default_options.rb b/config/initializers/faraday_default_options.rb new file mode 100644 index 0000000000..979dff3397 --- /dev/null +++ b/config/initializers/faraday_default_options.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module FaradayDefaultOptions + def new_builder(block) + super.tap do |builder| + # Sets headers and parses jsons automatically + builder.request :json + builder.response :json + + # Raises an error on 4xx and 5xx responses. + builder.response :raise_error + + # Logs requests and responses. + # By default, it only logs the request method and URL, and the request/response headers. + builder.response :logger, ::Logger.new($stdout), bodies: true if Rails.env.development? + end + end +end + +Faraday::ConnectionOptions.prepend(FaradayDefaultOptions) diff --git a/config/routes.rb b/config/routes.rb index 0fbbb03d9b..610915bbfc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -27,6 +27,7 @@ # https://github.com/plataformatec/devise/wiki/How-To:-Disable-user-from-destroying-their-account devise_for :users, skip: :registrations, controllers: { sessions: "sessions" } devise_scope :user do + get 'staging_login', to: 'sessions#staging_oauth_login' unless EnvConfig.WCA_LIVE_SITE? resource :registration, only: [:new, :create], path: 'users', @@ -39,6 +40,7 @@ post 'users/authenticate-sensitive' => 'users#authenticate_user_for_sensitive_edit' delete 'users/sign-out-other' => 'sessions#destroy_other', as: :destroy_other_user_sessions end + # TODO: This can be removed after deployment, this is so we don't have any users error out if they click on pay # while the deployment happens get 'registration/:id/payment-completion' => 'registrations#payment_completion_legacy', as: :registration_payment_completion_legacy diff --git a/env_config.rb b/env_config.rb index 8fb7ca27b5..a22b5ce931 100644 --- a/env_config.rb +++ b/env_config.rb @@ -81,6 +81,9 @@ # For server status optional :BUILD_TAG, :string, "local" + # To allow logging in to staging with your prod account + optional :STAGING_OAUTH_URL, :string, "" + # For Asset Compilation optional :ASSETS_COMPILATION, :bool, false end diff --git a/infra/wca_on_rails/staging/main.tf b/infra/wca_on_rails/staging/main.tf index bf4a6d8d5d..940637930c 100644 --- a/infra/wca_on_rails/staging/main.tf +++ b/infra/wca_on_rails/staging/main.tf @@ -32,6 +32,10 @@ locals { name = "SIDEKIQ_REDIS_URL" value = "redis://redis-main-staging-001.iebvzt.0001.usw2.cache.amazonaws.com:6379" }, + { + name = "STAGING_OAUTH_URL" + value = "https://www.worldcubeassociation.org" + }, { name = "STORAGE_AWS_BUCKET" value = aws_s3_bucket.storage-bucket.id