Skip to content

Commit

Permalink
feature flag privacy pass
Browse files Browse the repository at this point in the history
  • Loading branch information
mercedesb committed Mar 16, 2023
1 parent 4d67241 commit 4f44b20
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 7 deletions.
10 changes: 9 additions & 1 deletion app/controllers/concerns/privacy_pass_supportable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ module PrivacyPassSupportable
private

def setup_privacy_pass_challenge
return unless privacy_pass_enabled?

tokenizer = PrivacyPassTokenizer.new
tokenizer.register_challenge_for_redemption(session.id)
challenge = tokenizer.challenge_token
response.set_header("WWW-Authenticate", "PrivateToken challenge=#{challenge}, token-key=#{PrivacyPassTokenizer.issuer_public_key}")
end

def redeemed_privacy_pass_token?
def valid_privacy_pass_redemption?
return false unless privacy_pass_enabled?
return session[:redeemed_privacy_pass] unless session[:redeemed_privacy_pass].nil?

success = PrivacyPassRedeemer.call(request.headers["Authorization"], session.id)
Expand All @@ -21,4 +24,9 @@ def redeemed_privacy_pass_token?
def delete_privacy_pass_token_redemption
session.delete(:redeemed_privacy_pass)
end

def privacy_pass_enabled?
ld_context = LaunchDarkly::LDContext.with_key(self.class.name)
Rails.configuration.launch_darkly_client.variation("privacy_pass.enabled", ld_context, false)
end
end
7 changes: 4 additions & 3 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ class SessionsController < Clearance::SessionsController
before_action :redirect_to_new_mfa, if: :mfa_required_not_yet_enabled?, only: %i[verify authenticate]
before_action :redirect_to_settings_strong_mfa_required, if: :mfa_required_weak_level_enabled?, only: %i[verify authenticate]
before_action :ensure_not_blocked, only: :create
before_action :present_privacy_pass_challenge, unless: :redeemed_privacy_pass_token?, only: :new
before_action :present_privacy_pass_challenge, unless: :valid_privacy_pass_redemption?, only: :new
after_action :delete_mfa_expiry_session, only: %i[webauthn_create mfa_create]

def create
@user = find_user
if !redeemed_privacy_pass_token? && HcaptchaVerifier.should_verify_sign_in?(who)
if !valid_privacy_pass_redemption? && HcaptchaVerifier.should_verify_sign_in?(who)
setup_captcha_verification
render "sessions/captcha"
elsif @user && (@user.mfa_enabled? || @user.webauthn_credentials.any?)
Expand Down Expand Up @@ -200,7 +200,8 @@ def setup_captcha_verification

def present_privacy_pass_challenge
setup_privacy_pass_challenge
render "sessions/new", status: :unauthorized
status = privacy_pass_enabled? ? :unauthorized : :ok
render "sessions/new", status: status
end

def login_conditions_met?
Expand Down
7 changes: 4 additions & 3 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class UsersController < Clearance::UsersController
include CaptchaVerifiable
include PrivacyPassSupportable

before_action :present_privacy_pass_challenge, unless: :redeemed_privacy_pass_token?, only: :new
before_action :present_privacy_pass_challenge, unless: :valid_privacy_pass_redemption?, only: :new

def new
@user = user_from_params
Expand All @@ -11,7 +11,7 @@ def new
def create
@user = user_from_params
render template: "users/new" and return unless @user.valid?
if !redeemed_privacy_pass_token? && HcaptchaVerifier.should_verify_sign_up?(request.remote_ip)
if !valid_privacy_pass_redemption? && HcaptchaVerifier.should_verify_sign_up?(request.remote_ip)
setup_captcha_verification
render "users/captcha"
elsif @user.save
Expand Down Expand Up @@ -49,7 +49,8 @@ def setup_captcha_verification
def present_privacy_pass_challenge
@user = user_from_params
setup_privacy_pass_challenge
render "users/new", status: :unauthorized
status = privacy_pass_enabled? ? :unauthorized : :ok
render "users/new", status: status
end

def user_params
Expand Down
4 changes: 4 additions & 0 deletions test/integration/sign_in_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ class SignInTest < SystemTest
click_button "Verify"

StatsD.expects(:distribution)

assert page.has_content? "Multi-factor authentication"

within(".mfa-form") do
Expand All @@ -335,6 +336,7 @@ class SignInTest < SystemTest
end

test "signing in when privacy pass is verified" do
Rails.configuration.launch_darkly_client.expects(:variation).with("privacy_pass.enabled", anything, anything).returns(true).at_least_once
# privacy pass is meant to _not_ be machine automatable, so we're stubbing in this case
PrivacyPassRedeemer.expects(:call).with(anything, anything).returns(true)

Expand All @@ -347,6 +349,7 @@ class SignInTest < SystemTest
end

test "signing in when privacy pass is not verified and captcha is not triggered" do
Rails.configuration.launch_darkly_client.expects(:variation).with("privacy_pass.enabled", anything, anything).returns(true).at_least_once
# privacy pass is meant to _not_ be machine automatable, so we're stubbing in this case
PrivacyPassRedeemer.expects(:call).with(anything, anything).returns(false)

Expand All @@ -359,6 +362,7 @@ class SignInTest < SystemTest
end

test "signing in when privacy pass is not verified and captcha is triggered" do
Rails.configuration.launch_darkly_client.expects(:variation).with("privacy_pass.enabled", anything, anything).returns(true).at_least_once
@scope = Rack::Attack::LOGIN_THROTTLE_PER_USER_KEY
update_limit_for("#{@scope}:#{@user.email}", 4, Rack::Attack::LOGIN_LIMIT_PERIOD)
# captcha is meant to _not_ be machine automatable, so we're stubbing in this case
Expand Down
3 changes: 3 additions & 0 deletions test/integration/sign_up_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class SignUpTest < SystemTest
end

test "sign up when privacy pass is verified" do
Rails.configuration.launch_darkly_client.expects(:variation).with("privacy_pass.enabled", anything, anything).returns(true).at_least_once
# privacy pass is meant to _not_ be machine automatable, so we're stubbing in this case
PrivacyPassRedeemer.expects(:call).with(anything, anything).returns(true)

Expand All @@ -126,6 +127,7 @@ class SignUpTest < SystemTest
end

test "sign up when privacy pass is not verified and captcha is not triggered" do
Rails.configuration.launch_darkly_client.expects(:variation).with("privacy_pass.enabled", anything, anything).returns(true).at_least_once
# privacy pass is meant to _not_ be machine automatable, so we're stubbing in this case
PrivacyPassRedeemer.expects(:call).with(anything, anything).returns(false)

Expand All @@ -140,6 +142,7 @@ class SignUpTest < SystemTest
end

test "sign up when privacy pass is not verified and captcha verification is triggered" do
Rails.configuration.launch_darkly_client.expects(:variation).with("privacy_pass.enabled", anything, anything).returns(true).at_least_once
# privacy pass is meant to _not_ be machine automatable, so we're stubbing in this case
PrivacyPassRedeemer.expects(:call).with(anything, anything).returns(false)

Expand Down

0 comments on commit 4f44b20

Please sign in to comment.