Skip to content

Commit

Permalink
Adds a new "UI and gem signin" mfa_level to allow API Keys to skip MF…
Browse files Browse the repository at this point in the history
…A check

Fixes rubygems#2500
  • Loading branch information
iMacTia committed Jan 6, 2021
1 parent 10e4b3e commit fcf4a71
Show file tree
Hide file tree
Showing 13 changed files with 73 additions and 27 deletions.
2 changes: 1 addition & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class User < ApplicationRecord
unless: :skip_password_validation?
validate :unconfirmed_email_uniqueness

enum mfa_level: { disabled: 0, ui_only: 1, ui_and_api: 2 }, _prefix: :mfa
enum mfa_level: { disabled: 0, ui_only: 1, ui_and_api: 2, ui_and_gem_signin: 3 }, _prefix: :mfa

def self.authenticate(who, password)
user = find_by(email: who.downcase) || find_by(handle: who)
Expand Down
1 change: 1 addition & 0 deletions app/views/settings/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<%= label_tag :level, t(".mfa.level.title"), class: "form__label" %>
<%= select_tag :level, options_for_select([
[t(".mfa.level.ui_and_api"), "ui_and_api"],
[t(".mfa.level.ui_and_gem_signin"), "ui_and_gem_signin"],
[t(".mfa.level.ui_only"), "ui_only"],
[t(".mfa.level.disabled"), "disabled"]], @user.mfa_level), class: "form__input form__select" %>
<div class="text_field">
Expand Down
1 change: 1 addition & 0 deletions config/locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ de:
disabled:
ui_only:
ui_and_api:
ui_and_gem_signin:
profiles:
edit:
change_avatar:
Expand Down
1 change: 1 addition & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ en:
disabled: Disabled
ui_only: UI Only
ui_and_api: UI and API
ui_and_gem_signin: UI and gem signin
profiles:
edit:
change_avatar: Change Avatar
Expand Down
1 change: 1 addition & 0 deletions config/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ es:
disabled: Desactivada
ui_only: Solo Interfaz de Usuario
ui_and_api: Interfaz de Usuario y API
ui_and_gem_signin: Interfaz de Usario y gem signin
profiles:
edit:
change_avatar:
Expand Down
1 change: 1 addition & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ fr:
disabled:
ui_only:
ui_and_api:
ui_and_gem_signin:
profiles:
edit:
change_avatar:
Expand Down
1 change: 1 addition & 0 deletions config/locales/ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ ja:
disabled:
ui_only:
ui_and_api:
ui_and_gem_signin:
profiles:
edit:
change_avatar:
Expand Down
1 change: 1 addition & 0 deletions config/locales/nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ nl:
disabled:
ui_only:
ui_and_api:
ui_and_gem_signin:
profiles:
edit:
change_avatar:
Expand Down
1 change: 1 addition & 0 deletions config/locales/pt-BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ pt-BR:
disabled:
ui_only:
ui_and_api:
ui_and_gem_signin:
profiles:
edit:
change_avatar:
Expand Down
1 change: 1 addition & 0 deletions config/locales/zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ zh-CN:
disabled:
ui_only:
ui_and_api:
ui_and_gem_signin:
profiles:
edit:
change_avatar:
Expand Down
1 change: 1 addition & 0 deletions config/locales/zh-TW.yml
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ zh-TW:
disabled:
ui_only:
ui_and_api:
ui_and_gem_signin:
profiles:
edit:
change_avatar:
Expand Down
76 changes: 50 additions & 26 deletions test/functional/api/v1/rubygems_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,30 @@ def self.should_respond_to(format)
end
end

context "When mfa for UI and gem signin is enabled" do
setup do
@user.enable_mfa!(ROTP::Base32.random_base32, :ui_and_gem_signin)
end

context "On POST to create for new gem" do
setup do
post :create, body: gem_file.read
end
should respond_with :success
should "register new gem" do
assert_equal 1, Rubygem.count
assert_equal @user, Rubygem.last.versions.first.pusher
assert_equal "Successfully registered gem: test (0.0.0)", @response.body
end
should "add user as confirmed owner" do
ownership = Rubygem.last.ownerships.first

assert_equal @user, ownership.user
assert ownership.confirmed?
end
end
end

context "On POST to create for new gem" do
setup do
post :create, body: gem_file.read
Expand Down Expand Up @@ -300,13 +324,13 @@ def self.should_respond_to(format)

@date = 1.year.ago
@version = create(:version,
rubygem: rubygem,
number: "0.0.0",
updated_at: @date,
created_at: @date,
summary: "Freewill",
authors: ["Geddy Lee"],
built_at: @date)
rubygem: rubygem,
number: "0.0.0",
updated_at: @date,
created_at: @date,
summary: "Freewill",
authors: ["Geddy Lee"],
built_at: @date)

post :create, body: gem_file.read
end
Expand Down Expand Up @@ -377,13 +401,13 @@ def self.should_respond_to(format)
setup do
rubygem = create(:rubygem, name: "test")
create(:ownership,
rubygem: rubygem,
user: @user)
rubygem: rubygem,
user: @user)
create(:version,
rubygem: rubygem,
number: "0.0.0",
updated_at: 1.year.ago,
created_at: 1.year.ago)
rubygem: rubygem,
number: "0.0.0",
updated_at: 1.year.ago,
created_at: 1.year.ago)
end
should "POST to create for existing gem should not fail" do
requires_toxiproxy
Expand All @@ -407,7 +431,7 @@ def self.should_respond_to(format)
should "deny access" do
assert_response 401
assert_equal "Access Denied. Please sign up for an account at https://rubygems.org",
@response.body
@response.body
end
end

Expand Down Expand Up @@ -450,12 +474,12 @@ def self.should_respond_to(format)

context "on GET to reverse_dependencies" do
setup do
@dependency = create(:rubygem)
@gem_one = create(:rubygem)
@gem_two = create(:rubygem)
@gem_three = create(:rubygem)
version_one = create(:version, rubygem: @gem_one)
version_two = create(:version, rubygem: @gem_two)
@dependency = create(:rubygem)
@gem_one = create(:rubygem)
@gem_two = create(:rubygem)
@gem_three = create(:rubygem)
version_one = create(:version, rubygem: @gem_one)
version_two = create(:version, rubygem: @gem_two)
version_three = create(:version, rubygem: @gem_three)

create(:dependency, :runtime, version: version_one, rubygem: @dependency)
Expand All @@ -477,9 +501,9 @@ def self.should_respond_to(format)
context "with only=development" do
should "only return names of reverse development dependencies" do
get :reverse_dependencies,
params: { id: @dependency.to_param,
only: "development",
format: "json" }
params: { id: @dependency.to_param,
only: "development",
format: "json" }

gems = JSON.load(@response.body)

Expand All @@ -492,9 +516,9 @@ def self.should_respond_to(format)
context "with only=runtime" do
should "only return names of reverse development dependencies" do
get :reverse_dependencies,
params: { id: @dependency.to_param,
only: "runtime",
format: "json" }
params: { id: @dependency.to_param,
only: "runtime",
format: "json" }

gems = JSON.load(@response.body)

Expand Down
12 changes: 12 additions & 0 deletions test/functional/multifactor_auths_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ class MultifactorAuthsControllerTest < ActionController::TestCase
assert @user.reload.mfa_ui_and_api?
end
end

context "on updating to ui_and_gem_signin" do
setup do
put :update, params: { otp: ROTP::TOTP.new(@user.mfa_seed).now, level: "ui_and_gem_signin" }
end

should respond_with :redirect
should redirect_to("the settings page") { edit_settings_path }
should "update make mfa level to mfa_ui_and_gem_signin now" do
assert @user.reload.mfa_ui_and_gem_signin?
end
end
end
end

Expand Down

0 comments on commit fcf4a71

Please sign in to comment.