mirror of
https://github.com/discourse/discourse.git
synced 2025-06-03 14:04:36 +08:00
DEV: Introduce Auth::ManagedAuthenticator
A generic implementation of Auth::Authenticator which stores data in the new UserAssociatedAccount model. This should help significantly reduce the duplicated logic across different auth providers.
This commit is contained in:
148
spec/components/auth/managed_authenticator_spec.rb
Normal file
148
spec/components/auth/managed_authenticator_spec.rb
Normal file
@ -0,0 +1,148 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe Auth::ManagedAuthenticator do
|
||||
let(:authenticator) {
|
||||
Class.new(described_class) do
|
||||
def name; "myauth" end
|
||||
end.new
|
||||
}
|
||||
|
||||
let(:hash) {
|
||||
{
|
||||
provider: "myauth",
|
||||
uid: "1234",
|
||||
info: {
|
||||
name: "Best Display Name",
|
||||
email: "awesome@example.com",
|
||||
nickname: "IAmGroot"
|
||||
},
|
||||
credentials: {
|
||||
token: "supersecrettoken"
|
||||
},
|
||||
extra: {
|
||||
raw_info: {
|
||||
randominfo: "some info"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe 'after_authenticate' do
|
||||
it 'can match account from an existing association' do
|
||||
user = Fabricate(:user)
|
||||
associated = UserAssociatedAccount.create!(user: user, provider_name: 'myauth', provider_uid: "1234")
|
||||
result = authenticator.after_authenticate(hash)
|
||||
|
||||
expect(result.user.id).to eq(user.id)
|
||||
associated.reload
|
||||
expect(associated.info["name"]).to eq("Best Display Name")
|
||||
expect(associated.info["email"]).to eq("awesome@example.com")
|
||||
expect(associated.credentials["token"]).to eq("supersecrettoken")
|
||||
expect(associated.extra["raw_info"]["randominfo"]).to eq("some info")
|
||||
end
|
||||
|
||||
describe 'connecting to another user account' do
|
||||
let(:user1) { Fabricate(:user) }
|
||||
let(:user2) { Fabricate(:user) }
|
||||
before { UserAssociatedAccount.create!(user: user1, provider_name: 'myauth', provider_uid: "1234") }
|
||||
|
||||
it 'works by default' do
|
||||
result = authenticator.after_authenticate(hash, existing_account: user2)
|
||||
expect(result.user.id).to eq(user2.id)
|
||||
expect(UserAssociatedAccount.exists?(user_id: user1.id)).to eq(false)
|
||||
expect(UserAssociatedAccount.exists?(user_id: user2.id)).to eq(true)
|
||||
end
|
||||
|
||||
it 'does not work when disabled' do
|
||||
authenticator = Class.new(described_class) do
|
||||
def name; "myauth" end
|
||||
def can_connect_existing_user?; false end
|
||||
end.new
|
||||
result = authenticator.after_authenticate(hash, existing_account: user2)
|
||||
expect(result.user.id).to eq(user1.id)
|
||||
expect(UserAssociatedAccount.exists?(user_id: user1.id)).to eq(true)
|
||||
expect(UserAssociatedAccount.exists?(user_id: user2.id)).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'match by email' do
|
||||
it 'works normally' do
|
||||
user = Fabricate(:user)
|
||||
result = authenticator.after_authenticate(hash.deep_merge(info: { email: user.email }))
|
||||
expect(result.user.id).to eq(user.id)
|
||||
expect(UserAssociatedAccount.find_by(provider_name: 'myauth', provider_uid: "1234").user_id).to eq(user.id)
|
||||
end
|
||||
|
||||
it 'works if there is already an association with the target account' do
|
||||
user = Fabricate(:user, email: "awesome@example.com")
|
||||
result = authenticator.after_authenticate(hash)
|
||||
expect(result.user.id).to eq(user.id)
|
||||
end
|
||||
|
||||
it 'does not match if match_by_email is false' do
|
||||
authenticator = Class.new(described_class) do
|
||||
def name; "myauth" end
|
||||
def match_by_email; false end
|
||||
end.new
|
||||
user = Fabricate(:user, email: "awesome@example.com")
|
||||
result = authenticator.after_authenticate(hash)
|
||||
expect(result.user).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no matching user' do
|
||||
it 'returns the correct information' do
|
||||
result = authenticator.after_authenticate(hash)
|
||||
expect(result.user).to eq(nil)
|
||||
expect(result.username).to eq("IAmGroot")
|
||||
expect(result.email).to eq("awesome@example.com")
|
||||
end
|
||||
|
||||
it 'works if there is already an association with the target account' do
|
||||
user = Fabricate(:user, email: "awesome@example.com")
|
||||
result = authenticator.after_authenticate(hash)
|
||||
expect(result.user.id).to eq(user.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'description_for_user' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
it 'returns empty string if no entry for user' do
|
||||
expect(authenticator.description_for_user(user)).to eq("")
|
||||
end
|
||||
|
||||
it 'returns correct information' do
|
||||
association = UserAssociatedAccount.create!(user: user, provider_name: 'myauth', provider_uid: "1234", info: { nickname: "somenickname", email: "test@domain.tld", name: "bestname" })
|
||||
expect(authenticator.description_for_user(user)).to eq('test@domain.tld')
|
||||
association.update(info: { nickname: "somenickname", name: "bestname" })
|
||||
expect(authenticator.description_for_user(user)).to eq('somenickname')
|
||||
association.update(info: { nickname: "bestname" })
|
||||
expect(authenticator.description_for_user(user)).to eq('bestname')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'revoke' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
it 'raises exception if no entry for user' do
|
||||
expect { authenticator.revoke(user) }.to raise_error(Discourse::NotFound)
|
||||
end
|
||||
|
||||
context "with valid record" do
|
||||
before do
|
||||
UserAssociatedAccount.create!(user: user, provider_name: 'myauth', provider_uid: "1234", info: { name: "somename" })
|
||||
end
|
||||
|
||||
it 'revokes correctly' do
|
||||
expect(authenticator.description_for_user(user)).to eq("somename")
|
||||
expect(authenticator.can_revoke?).to eq(true)
|
||||
expect(authenticator.revoke(user)).to eq(true)
|
||||
|
||||
expect(authenticator.description_for_user(user)).to eq("")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Reference in New Issue
Block a user