2019-04-29 20:27:42 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-08-21 19:14:26 -04:00
|
|
|
def auth_token_for(user)
|
|
|
|
{
|
2020-11-10 05:09:15 -05:00
|
|
|
provider: "github",
|
2017-08-21 19:14:26 -04:00
|
|
|
extra: {
|
|
|
|
all_emails: [{ email: user.email, primary: true, verified: true }],
|
|
|
|
},
|
|
|
|
info: {
|
|
|
|
email: user.email,
|
|
|
|
nickname: user.username,
|
|
|
|
name: user.name,
|
|
|
|
image: "https://avatars3.githubusercontent.com/u/#{user.username}",
|
|
|
|
},
|
|
|
|
uid: "100",
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2022-07-27 22:27:38 -04:00
|
|
|
RSpec.describe Auth::GithubAuthenticator do
|
2017-08-21 19:14:26 -04:00
|
|
|
let(:authenticator) { described_class.new }
|
2023-11-09 17:47:59 -05:00
|
|
|
fab!(:user)
|
2016-09-22 14:31:10 -04:00
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
describe "after_authenticate" do
|
2020-11-10 05:09:15 -05:00
|
|
|
let(:data) { auth_token_for(user) }
|
2016-09-22 14:31:10 -04:00
|
|
|
|
2018-05-29 23:54:12 -04:00
|
|
|
it "can authenticate and create a user record for already existing users" do
|
|
|
|
result = authenticator.after_authenticate(data)
|
2016-09-22 14:31:10 -04:00
|
|
|
|
|
|
|
expect(result.user.id).to eq(user.id)
|
|
|
|
expect(result.username).to eq(user.username)
|
|
|
|
expect(result.name).to eq(user.name)
|
|
|
|
expect(result.email).to eq(user.email)
|
|
|
|
expect(result.email_valid).to eq(true)
|
2018-05-29 23:54:12 -04:00
|
|
|
|
2021-05-20 21:43:47 -04:00
|
|
|
# Authenticates again when user has GitHub user info
|
2018-05-29 23:54:12 -04:00
|
|
|
result = authenticator.after_authenticate(data)
|
|
|
|
|
|
|
|
expect(result.email).to eq(user.email)
|
|
|
|
expect(result.email_valid).to eq(true)
|
2016-09-22 14:31:10 -04:00
|
|
|
end
|
|
|
|
|
2020-04-23 11:24:26 -04:00
|
|
|
it "can authenticate and update GitHub screen_name for existing user" do
|
2020-11-10 05:09:15 -05:00
|
|
|
UserAssociatedAccount.create!(
|
|
|
|
user_id: user.id,
|
|
|
|
provider_name: "github",
|
|
|
|
provider_uid: 100,
|
|
|
|
info: {
|
|
|
|
nickname: "boris",
|
|
|
|
},
|
|
|
|
)
|
2020-04-23 11:24:26 -04:00
|
|
|
|
|
|
|
result = authenticator.after_authenticate(data)
|
|
|
|
|
|
|
|
expect(result.user.id).to eq(user.id)
|
|
|
|
expect(result.email).to eq(user.email)
|
|
|
|
expect(result.email_valid).to eq(true)
|
2020-11-10 05:09:15 -05:00
|
|
|
expect(
|
|
|
|
UserAssociatedAccount.find_by(provider_name: "github", user_id: user.id).info["nickname"],
|
|
|
|
).to eq(user.username)
|
2020-04-23 11:24:26 -04:00
|
|
|
end
|
|
|
|
|
2018-03-19 07:40:35 -04:00
|
|
|
it "should use primary email for new user creation over other available emails" do
|
|
|
|
hash = {
|
2020-11-10 05:09:15 -05:00
|
|
|
provider: "github",
|
2018-03-19 07:40:35 -04:00
|
|
|
extra: {
|
|
|
|
all_emails: [
|
|
|
|
{ email: "bob@example.com", primary: false, verified: true },
|
|
|
|
{ email: "john@example.com", primary: true, verified: true },
|
|
|
|
],
|
|
|
|
},
|
|
|
|
info: {
|
|
|
|
email: "john@example.com",
|
|
|
|
nickname: "john",
|
|
|
|
name: "John Bob",
|
|
|
|
},
|
|
|
|
uid: "100",
|
|
|
|
}
|
|
|
|
|
|
|
|
result = authenticator.after_authenticate(hash)
|
|
|
|
|
|
|
|
expect(result.email).to eq("john@example.com")
|
|
|
|
end
|
|
|
|
|
2018-10-10 00:46:50 -04:00
|
|
|
it "should not error out if user already has a different old github account attached" do
|
|
|
|
# There is a rare case where an end user had
|
|
|
|
# 2 different github accounts and moved emails between the 2
|
|
|
|
|
2020-11-10 05:09:15 -05:00
|
|
|
UserAssociatedAccount.create!(
|
|
|
|
user_id: user.id,
|
|
|
|
info: {
|
|
|
|
nickname: "bob",
|
|
|
|
},
|
|
|
|
provider_uid: 100,
|
|
|
|
provider_name: "github",
|
|
|
|
)
|
2018-10-10 00:46:50 -04:00
|
|
|
|
|
|
|
hash = {
|
2020-11-10 05:09:15 -05:00
|
|
|
provider: "github",
|
2018-10-10 00:46:50 -04:00
|
|
|
extra: {
|
|
|
|
all_emails: [{ email: user.email, primary: false, verified: true }],
|
|
|
|
},
|
|
|
|
info: {
|
|
|
|
email: "john@example.com",
|
|
|
|
nickname: "john",
|
|
|
|
name: "John Bob",
|
|
|
|
},
|
|
|
|
uid: "1001",
|
|
|
|
}
|
|
|
|
|
|
|
|
result = authenticator.after_authenticate(hash)
|
|
|
|
|
|
|
|
expect(result.user.id).to eq(user.id)
|
2020-11-10 05:09:15 -05:00
|
|
|
expect(UserAssociatedAccount.where(user_id: user.id).pluck(:provider_uid)).to eq(["1001"])
|
2018-10-10 00:46:50 -04:00
|
|
|
end
|
|
|
|
|
2016-09-22 14:31:10 -04:00
|
|
|
it "will not authenticate for already existing users with an unverified email" do
|
|
|
|
hash = {
|
2020-11-10 05:09:15 -05:00
|
|
|
provider: "github",
|
2016-09-22 14:31:10 -04:00
|
|
|
extra: {
|
|
|
|
all_emails: [{ email: user.email, primary: true, verified: false }],
|
|
|
|
},
|
|
|
|
info: {
|
|
|
|
email: user.email,
|
|
|
|
nickname: user.username,
|
|
|
|
name: user.name,
|
|
|
|
},
|
|
|
|
uid: "100",
|
|
|
|
}
|
|
|
|
|
|
|
|
result = authenticator.after_authenticate(hash)
|
|
|
|
|
|
|
|
expect(result.user).to eq(nil)
|
|
|
|
expect(result.username).to eq(user.username)
|
|
|
|
expect(result.name).to eq(user.name)
|
|
|
|
expect(result.email).to eq(user.email)
|
|
|
|
expect(result.email_valid).to eq(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can create a proper result for non existing users" do
|
|
|
|
hash = {
|
2020-11-10 05:09:15 -05:00
|
|
|
provider: "github",
|
2016-09-22 14:31:10 -04:00
|
|
|
extra: {
|
|
|
|
all_emails: [{ email: "person@example.com", primary: true, verified: true }],
|
|
|
|
},
|
|
|
|
info: {
|
|
|
|
email: "person@example.com",
|
|
|
|
nickname: "person",
|
|
|
|
name: "Person Lastname",
|
|
|
|
},
|
|
|
|
uid: "100",
|
|
|
|
}
|
|
|
|
|
|
|
|
result = authenticator.after_authenticate(hash)
|
|
|
|
|
|
|
|
expect(result.user).to eq(nil)
|
|
|
|
expect(result.username).to eq(hash[:info][:nickname])
|
|
|
|
expect(result.name).to eq(hash[:info][:name])
|
|
|
|
expect(result.email).to eq(hash[:info][:email])
|
2018-01-11 23:17:29 -05:00
|
|
|
expect(result.email_valid).to eq(hash[:info][:email].present?)
|
2016-09-22 14:31:10 -04:00
|
|
|
end
|
|
|
|
|
2020-07-26 20:23:54 -04:00
|
|
|
it "will skip blocklisted domains for non existing users" do
|
2016-09-22 14:31:10 -04:00
|
|
|
hash = {
|
2020-11-10 05:09:15 -05:00
|
|
|
provider: "github",
|
2016-09-22 14:31:10 -04:00
|
|
|
extra: {
|
|
|
|
all_emails: [
|
2020-07-26 20:23:54 -04:00
|
|
|
{ email: "not_allowed@blocklist.com", primary: true, verified: true },
|
|
|
|
{ email: "allowed@allowlist.com", primary: false, verified: true },
|
2016-09-22 14:31:10 -04:00
|
|
|
],
|
|
|
|
},
|
|
|
|
info: {
|
2020-07-26 20:23:54 -04:00
|
|
|
email: "not_allowed@blocklist.com",
|
2016-09-22 14:31:10 -04:00
|
|
|
nickname: "person",
|
|
|
|
name: "Person Lastname",
|
|
|
|
},
|
|
|
|
uid: "100",
|
|
|
|
}
|
|
|
|
|
2020-07-26 20:23:54 -04:00
|
|
|
SiteSetting.blocked_email_domains = "blocklist.com"
|
2016-09-22 14:31:10 -04:00
|
|
|
result = authenticator.after_authenticate(hash)
|
|
|
|
|
|
|
|
expect(result.user).to eq(nil)
|
|
|
|
expect(result.username).to eq(hash[:info][:nickname])
|
|
|
|
expect(result.name).to eq(hash[:info][:name])
|
2020-07-26 20:23:54 -04:00
|
|
|
expect(result.email).to eq("allowed@allowlist.com")
|
2016-09-22 14:31:10 -04:00
|
|
|
expect(result.email_valid).to eq(true)
|
|
|
|
end
|
|
|
|
|
2020-07-26 20:23:54 -04:00
|
|
|
it "will find allowlisted domains for non existing users" do
|
2016-09-22 14:31:10 -04:00
|
|
|
hash = {
|
2020-11-10 05:09:15 -05:00
|
|
|
provider: "github",
|
2016-09-22 14:31:10 -04:00
|
|
|
extra: {
|
|
|
|
all_emails: [
|
|
|
|
{ email: "person@example.com", primary: true, verified: true },
|
2020-07-26 20:23:54 -04:00
|
|
|
{ email: "not_allowed@blocklist.com", primary: false, verified: true },
|
|
|
|
{ email: "allowed@allowlist.com", primary: false, verified: true },
|
2016-09-22 14:31:10 -04:00
|
|
|
],
|
|
|
|
},
|
|
|
|
info: {
|
|
|
|
email: "person@example.com",
|
|
|
|
nickname: "person",
|
|
|
|
name: "Person Lastname",
|
|
|
|
},
|
|
|
|
uid: "100",
|
|
|
|
}
|
|
|
|
|
2020-07-26 20:23:54 -04:00
|
|
|
SiteSetting.allowed_email_domains = "allowlist.com"
|
2016-09-22 14:31:10 -04:00
|
|
|
result = authenticator.after_authenticate(hash)
|
|
|
|
|
|
|
|
expect(result.user).to eq(nil)
|
|
|
|
expect(result.username).to eq(hash[:info][:nickname])
|
|
|
|
expect(result.name).to eq(hash[:info][:name])
|
2020-07-26 20:23:54 -04:00
|
|
|
expect(result.email).to eq("allowed@allowlist.com")
|
2016-09-22 14:31:10 -04:00
|
|
|
expect(result.email_valid).to eq(true)
|
|
|
|
end
|
|
|
|
|
2018-07-27 12:18:53 -04:00
|
|
|
it "can connect to a different existing user account" do
|
|
|
|
user1 = Fabricate(:user)
|
|
|
|
user2 = Fabricate(:user)
|
|
|
|
|
2018-12-09 17:27:00 -05:00
|
|
|
expect(authenticator.can_connect_existing_user?).to eq(true)
|
|
|
|
|
2020-11-10 05:09:15 -05:00
|
|
|
UserAssociatedAccount.create!(
|
|
|
|
provider_name: "github",
|
|
|
|
user_id: user1.id,
|
|
|
|
provider_uid: 100,
|
|
|
|
info: {
|
|
|
|
nickname: "boris",
|
|
|
|
},
|
|
|
|
)
|
2018-07-27 12:18:53 -04:00
|
|
|
|
|
|
|
result = authenticator.after_authenticate(data, existing_account: user2)
|
|
|
|
|
|
|
|
expect(result.user.id).to eq(user2.id)
|
2020-11-10 05:09:15 -05:00
|
|
|
expect(UserAssociatedAccount.exists?(user_id: user1.id)).to eq(false)
|
|
|
|
expect(UserAssociatedAccount.exists?(user_id: user2.id)).to eq(true)
|
2018-07-27 12:18:53 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
describe "revoke" do
|
2023-11-09 17:47:59 -05:00
|
|
|
fab!(:user)
|
2018-07-27 12:18:53 -04:00
|
|
|
let(:authenticator) { Auth::GithubAuthenticator.new }
|
|
|
|
|
|
|
|
it "raises exception if no entry for user" do
|
|
|
|
expect { authenticator.revoke(user) }.to raise_error(Discourse::NotFound)
|
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
it "revokes correctly" do
|
|
|
|
UserAssociatedAccount.create!(
|
|
|
|
provider_name: "github",
|
|
|
|
user_id: user.id,
|
|
|
|
provider_uid: 100,
|
|
|
|
info: {
|
|
|
|
nickname: "boris",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
expect(authenticator.can_revoke?).to eq(true)
|
|
|
|
expect(authenticator.revoke(user)).to eq(true)
|
|
|
|
expect(authenticator.description_for_user(user)).to eq("")
|
|
|
|
end
|
2016-09-22 14:31:10 -04:00
|
|
|
end
|
2017-08-21 19:14:26 -04:00
|
|
|
|
|
|
|
describe "avatar retrieval" do
|
2017-08-22 23:46:50 -04:00
|
|
|
let(:job_klass) { Jobs::DownloadAvatarFromUrl }
|
|
|
|
|
2017-08-21 19:14:26 -04:00
|
|
|
context "when user has a custom avatar" do
|
2019-05-06 23:12:20 -04:00
|
|
|
fab!(:user_avatar) { Fabricate(:user_avatar, custom_upload: Fabricate(:upload)) }
|
|
|
|
fab!(:user_with_custom_avatar) { Fabricate(:user, user_avatar: user_avatar) }
|
2017-08-21 19:14:26 -04:00
|
|
|
|
|
|
|
it "does not enqueue a download_avatar_from_url job" do
|
2017-08-22 23:46:50 -04:00
|
|
|
expect {
|
|
|
|
authenticator.after_authenticate(auth_token_for(user_with_custom_avatar))
|
|
|
|
}.to_not change(job_klass.jobs, :size)
|
2017-08-21 19:14:26 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when user does not have a custom avatar" do
|
|
|
|
it "enqueues a download_avatar_from_url job" do
|
2017-08-22 23:46:50 -04:00
|
|
|
expect { authenticator.after_authenticate(auth_token_for(user)) }.to change(
|
|
|
|
job_klass.jobs,
|
|
|
|
:size,
|
|
|
|
).by(1)
|
|
|
|
|
|
|
|
job_args = job_klass.jobs.last["args"].first
|
|
|
|
|
|
|
|
expect(job_args["url"]).to eq("https://avatars3.githubusercontent.com/u/#{user.username}")
|
|
|
|
expect(job_args["user_id"]).to eq(user.id)
|
|
|
|
expect(job_args["override_gravatar"]).to eq(false)
|
2017-08-21 19:14:26 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-09-22 14:31:10 -04:00
|
|
|
end
|