Skip to content

Commit

Permalink
Allow logging into unverified accounts
Browse files Browse the repository at this point in the history
When the user logs in via an external provider, we can consider that
proof of them owning the email account. In that case, we can
automatically verify the account and proceed with the login.
  • Loading branch information
janko committed Jun 4, 2024
1 parent 4c5e047 commit 159b940
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 5 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,17 @@ end
account_from_omniauth {} # disable finding existing accounts for new identities
```

If the account associated to the external identity exists and is unverified (e.g. it was created through normal registration), the callback phase will return an error response, as only verified accounts can be logged into. You can change the default error flash and redirect location in this case:
#### Account verification

If the account associated to the external identity exists and is unverified (e.g. it was created through normal registration), the callback phase will automatically verify the account and login, assuming the `verify_account` feature is enabled and external email is the same.

If you wish to disallow OmniAuth login into unverified accounts, set the following:

```rb
omniauth_verify_account? false
```

You can change the default error flash and redirect location in this case:

```rb
omniauth_login_unverified_account_error_flash "The account matching the external identity is currently awaiting verification"
Expand Down
25 changes: 22 additions & 3 deletions lib/rodauth/features/omniauth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ module Rodauth
auth_value_method :omniauth_identities_provider_column, :provider
auth_value_method :omniauth_identities_uid_column, :uid

auth_value_methods(
:omniauth_verify_account?,
)

auth_methods(
:create_omniauth_identity,
:omniauth_identity_insert_hash,
Expand Down Expand Up @@ -62,9 +66,13 @@ def _handle_omniauth_callback
end

if account && !open_account?
set_response_error_reason_status(:unverified_account, unopen_account_error_status)
set_redirect_error_flash omniauth_login_unverified_account_error_flash
redirect omniauth_login_failure_redirect
if omniauth_verify_account?
omniauth_verify_account
else
set_response_error_reason_status(:unverified_account, unopen_account_error_status)
set_redirect_error_flash omniauth_login_unverified_account_error_flash
redirect omniauth_login_failure_redirect
end
end

transaction do
Expand Down Expand Up @@ -133,6 +141,17 @@ def allow_email_auth?

attr_reader :omniauth_identity

def omniauth_verify_account?
features.include?(:verify_account) && account[login_column] == omniauth_email
end

def omniauth_verify_account
transaction do
verify_account
remove_verify_account_key
end
end

def _omniauth_new_account(login)
acc = { login_column => login }
unless skip_status_checks?
Expand Down
30 changes: 29 additions & 1 deletion test/omniauth_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,35 @@
assert_equal 1, DB[:accounts].count
end

it "doesn't log in unverified accounts" do
it "verifies unverified accounts by default" do
DB[:accounts].delete

rodauth do
enable :omniauth, :verify_account
omniauth_provider :developer
create_account_set_password? true
create_account_autologin? false
end
roda do |r|
r.rodauth
r.root do
view content: "Verified: #{rodauth.account! && rodauth.open_account?}"
end
end

visit "/create-account"
fill_in "Login", with: "[email protected]"
fill_in "Password", with: "secret"
fill_in "Confirm Password", with: "secret"
click_on "Create Account"
assert_equal "An email has been sent to you with a link to verify your account", page.find("#notice_flash").text

omniauth_login "/auth/developer"
assert_equal "You have been logged in", page.find("#notice_flash").text
assert_includes page.html, "Verified: true"
end

it "rejects unverified accounts if verify_account feature is not loaded" do
DB[:accounts].update(status_id: 1)

rodauth do
Expand Down
10 changes: 10 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
require "bcrypt"
require "rack/session/cookie"
require "rodauth/model"
require "mail"

Mail.defaults { delivery_method :test }

DB = Sequel.connect("#{"jdbc:" if RUBY_ENGINE == "jruby"}sqlite::memory")

Expand All @@ -33,6 +36,13 @@
unique [:provider, :uid]
end

DB.create_table :account_verification_keys do
foreign_key :id, :accounts, primary_key: true
String :key, null: false
DateTime :requested_at, null: false, default: Sequel::CURRENT_TIMESTAMP
DateTime :email_last_sent, null: false, default: Sequel::CURRENT_TIMESTAMP
end

Sequel::Model.cache_anonymous_models = false

OmniAuth.config.allowed_request_methods = %i[get post]
Expand Down

0 comments on commit 159b940

Please sign in to comment.