mirror of
https://github.com/discourse/discourse.git
synced 2025-05-21 18:12:32 +08:00
major refactor of auth, break up the gigantic omniauth controller into sub classes for way better extensibitily
This commit is contained in:
24
lib/auth/authenticator.rb
Normal file
24
lib/auth/authenticator.rb
Normal file
@ -0,0 +1,24 @@
|
||||
# this class is used by the user and omniauth controllers, it controls how
|
||||
# an authentication system interacts with our database
|
||||
|
||||
module Auth; end
|
||||
|
||||
require 'auth/result'
|
||||
|
||||
class Auth::Authenticator
|
||||
def after_authenticate(auth_options)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
# can be used to hook in afete the authentication process
|
||||
# to ensure records exist for the provider in the db
|
||||
# this MUST be implemented for authenticators that do not
|
||||
# trust email
|
||||
def after_create_account(user, auth)
|
||||
# not required
|
||||
end
|
||||
|
||||
def lookup_user(user_info, email)
|
||||
user_info.try(:user) || User.where(email: email).first
|
||||
end
|
||||
end
|
42
lib/auth/cas_authenticator.rb
Normal file
42
lib/auth/cas_authenticator.rb
Normal file
@ -0,0 +1,42 @@
|
||||
class Auth::CasAuthenticator < Auth::Authenticator
|
||||
|
||||
def name
|
||||
'cas'
|
||||
end
|
||||
|
||||
def after_authenticate(auth_token)
|
||||
result = Auth::Result.new
|
||||
|
||||
email = auth_token[:info][:email] if auth_token[:info]
|
||||
email ||= if SiteSetting.cas_domainname.present?
|
||||
"#{auth_token[:extra][:user]}@#{SiteSetting.cas_domainname}"
|
||||
else
|
||||
auth_token[:extra][:user]
|
||||
end
|
||||
|
||||
result.email = email
|
||||
result.email_valid = true
|
||||
|
||||
result.username = username = auth_token[:extra][:user]
|
||||
|
||||
result.name = name = if auth_token[:info] && auth_token[:info][:name]
|
||||
auth_token[:info][:name]
|
||||
else
|
||||
auth_token["uid"]
|
||||
end
|
||||
|
||||
cas_user_id = auth_token["uid"]
|
||||
|
||||
result.extra_data = {
|
||||
cas_user_id: cas_user_id
|
||||
}
|
||||
|
||||
user_info = CasUserInfo.where(:cas_user_id => cas_user_id ).first
|
||||
|
||||
result.user = user_info.try(:user)
|
||||
result.user ||= User.where(email: email).first
|
||||
# TODO, create CAS record ?
|
||||
|
||||
result
|
||||
end
|
||||
end
|
56
lib/auth/facebook_authenticator.rb
Normal file
56
lib/auth/facebook_authenticator.rb
Normal file
@ -0,0 +1,56 @@
|
||||
class Auth::FacebookAuthenticator < Auth::Authenticator
|
||||
|
||||
def name
|
||||
"facebook"
|
||||
end
|
||||
|
||||
def after_authenticate(auth_token)
|
||||
|
||||
result = Auth::Result.new
|
||||
|
||||
session_info = parse_auth_token(auth_token)
|
||||
facebook_hash = session_info[:facebook]
|
||||
|
||||
result.email = email = session_info[:email]
|
||||
result.name = name = facebook_hash[:name]
|
||||
|
||||
result.extra_info = facebook_hash
|
||||
|
||||
user_info = FacebookUserInfo.where(facebook_user_id: facebook_hash[:facebook_user_id]).first
|
||||
|
||||
if result.user = lookup_user(user_info, email) && !user_info
|
||||
user.create_facebook_user_info! facebook_hash
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def after_create_account(user, auth)
|
||||
data = auth[:extra_data]
|
||||
FacebookUserInfo.create({user_id: user.id}.merge(data))
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def parse_auth_token(auth_token)
|
||||
|
||||
raw_info = auth_token["extra"]["raw_info"]
|
||||
email = auth_token["info"][:email]
|
||||
|
||||
{
|
||||
facebook: {
|
||||
facebook_user_id: auth_token["uid"],
|
||||
link: raw_info["link"],
|
||||
username: raw_info["username"],
|
||||
first_name: raw_info["first_name"],
|
||||
last_name: raw_info["last_name"],
|
||||
email: email,
|
||||
gender: raw_info["gender"],
|
||||
name: raw_info["name"]
|
||||
},
|
||||
email: email,
|
||||
email_valid: true
|
||||
}
|
||||
|
||||
end
|
||||
end
|
48
lib/auth/github_authenticator.rb
Normal file
48
lib/auth/github_authenticator.rb
Normal file
@ -0,0 +1,48 @@
|
||||
class Auth::GithubAuthenticator < Auth::Authenticator
|
||||
|
||||
def name
|
||||
"github"
|
||||
end
|
||||
|
||||
def after_authenticate(auth_token)
|
||||
result = Auth::Result.new
|
||||
|
||||
data = auth_token[:info]
|
||||
|
||||
result.username = screen_name = data["nickname"]
|
||||
result.email = email = data["email"]
|
||||
|
||||
github_user_id = auth_token["uid"]
|
||||
|
||||
result.extra_data = {
|
||||
github_user_id: github_user_id,
|
||||
github_screen_name: screen_name,
|
||||
}
|
||||
|
||||
user_info = GithubUserInfo.where(github_user_id: github_user_id).first
|
||||
|
||||
if user_info
|
||||
user = user_info.user
|
||||
elsif user = User.find_by_email(email)
|
||||
user_info = GithubUserInfo.create(
|
||||
user_id: user.id,
|
||||
screen_name: screen_name,
|
||||
github_user_id: github_user_id
|
||||
)
|
||||
end
|
||||
|
||||
result.user = user
|
||||
result.email_valid = true
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def after_create_account(user, auth)
|
||||
data = auth[:extra_data]
|
||||
GithubUserInfo.create(
|
||||
user_id: user.id,
|
||||
screen_name: data[:github_screen_name],
|
||||
github_user_id: data[:github_user_id]
|
||||
)
|
||||
end
|
||||
end
|
55
lib/auth/oauth2_authenticator.rb
Normal file
55
lib/auth/oauth2_authenticator.rb
Normal file
@ -0,0 +1,55 @@
|
||||
class Auth::OAuth2Authenticator < Auth::Authenticator
|
||||
|
||||
def name
|
||||
@name
|
||||
end
|
||||
|
||||
# only option at the moment is :trusted
|
||||
def initialize(name, opts={})
|
||||
@name = name
|
||||
@opts = opts
|
||||
end
|
||||
|
||||
def after_authenticate(auth_token)
|
||||
|
||||
result = Auth::Result.new
|
||||
|
||||
oauth2_provider = auth_token[:provider]
|
||||
oauth2_uid = auth_token[:uid]
|
||||
data = auth_token[:info]
|
||||
result.email = email = data[:email]
|
||||
result.name = name = data[:name]
|
||||
|
||||
oauth2_user_info = Oauth2UserInfo.where(uid: oauth2_uid, provider: oauth2_provider).first
|
||||
|
||||
if !oauth2_user_info && @opts[:trusted] && user = User.find_by_email(email)
|
||||
oauth2_user_info = Oauth2UserInfo.create(uid: oauth2_uid,
|
||||
provider: oauth2_provider,
|
||||
name: name,
|
||||
email: email,
|
||||
user: user)
|
||||
end
|
||||
|
||||
result.user = oauth2_user_info.try(:user)
|
||||
result.email_valid = @opts[:trusted]
|
||||
|
||||
result.extra_data = {
|
||||
uid: oauth2_uid,
|
||||
provider: oauth2_provider
|
||||
}
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def after_create_account(user, auth)
|
||||
data = auth[:extra_data]
|
||||
Oauth2UserInfo.create(
|
||||
uid: data[:uid],
|
||||
provider: data[:provider],
|
||||
name: auth[:name],
|
||||
email: auth[:email],
|
||||
user_id: user.id
|
||||
)
|
||||
end
|
||||
|
||||
end
|
38
lib/auth/open_id_authenticator.rb
Normal file
38
lib/auth/open_id_authenticator.rb
Normal file
@ -0,0 +1,38 @@
|
||||
class Auth::OpenIdAuthenticator < Auth::Authenticator
|
||||
|
||||
def initialize(name, opts = {})
|
||||
@name = name
|
||||
@opts = opts
|
||||
end
|
||||
|
||||
def name
|
||||
@name
|
||||
end
|
||||
|
||||
def after_authenticate(auth_token)
|
||||
|
||||
result = Auth::Result.new
|
||||
|
||||
data = auth_token[:info]
|
||||
identity_url = auth_token[:extra][:identity_url]
|
||||
result.email = email = data[:email]
|
||||
|
||||
# If the auth supplies a name / username, use those. Otherwise start with email.
|
||||
result.name = name = data[:name] || data[:email]
|
||||
result.username = username = data[:nickname] || data[:email]
|
||||
|
||||
user_open_id = UserOpenId.find_by_url(identity_url)
|
||||
|
||||
if !user_open_id && @opts[:trusted] && user = User.find_by_email(email)
|
||||
user_open_id = UserOpenId.create(url: identity_url , user_id: user.id, email: email, active: true)
|
||||
end
|
||||
|
||||
result.user = user_open_id.try(:user)
|
||||
result.extra_data = {
|
||||
openid_url: identity_url
|
||||
}
|
||||
result.email_valid = @opts[:trusted]
|
||||
|
||||
result
|
||||
end
|
||||
end
|
18
lib/auth/persona_authenticator.rb
Normal file
18
lib/auth/persona_authenticator.rb
Normal file
@ -0,0 +1,18 @@
|
||||
class Auth::PersonaAuthenticator < Auth::Authenticator
|
||||
|
||||
def name
|
||||
"persona"
|
||||
end
|
||||
|
||||
# TODO twitter provides all sorts of extra info, like website/bio etc.
|
||||
# it may be worth considering pulling some of it in.
|
||||
def after_authenticate(auth_token)
|
||||
result = Auth::Result.new
|
||||
|
||||
result.email = email = auth_token[:info][:email]
|
||||
result.email_valid = true
|
||||
|
||||
result.user = User.find_by_email(email)
|
||||
result
|
||||
end
|
||||
end
|
35
lib/auth/result.rb
Normal file
35
lib/auth/result.rb
Normal file
@ -0,0 +1,35 @@
|
||||
class Auth::Result
|
||||
attr_accessor :user, :name, :username, :email, :user,
|
||||
:email_valid, :extra_data, :awaiting_activation,
|
||||
:awaiting_approval, :authenticated, :authenticator_name
|
||||
|
||||
def session_data
|
||||
{
|
||||
email: email,
|
||||
username: username,
|
||||
email_valid: email_valid,
|
||||
name: name,
|
||||
authenticator_name: authenticator_name,
|
||||
extra_data: extra_data
|
||||
}
|
||||
end
|
||||
|
||||
def to_client_hash
|
||||
if user
|
||||
{
|
||||
authenticated: !!authenticated,
|
||||
awaiting_activation: !!awaiting_activation,
|
||||
awaiting_approval: !!awaiting_approval
|
||||
}
|
||||
else
|
||||
{
|
||||
email: email,
|
||||
name: User.suggest_name(name || username || email),
|
||||
username: UserNameSuggester.suggest(username || name || email),
|
||||
# this feels a tad wrong
|
||||
auth_provider: authenticator_name.capitalize,
|
||||
email_valid: !!email_valid
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
40
lib/auth/twitter_authenticator.rb
Normal file
40
lib/auth/twitter_authenticator.rb
Normal file
@ -0,0 +1,40 @@
|
||||
class Auth::TwitterAuthenticator < Auth::Authenticator
|
||||
|
||||
def name
|
||||
"twitter"
|
||||
end
|
||||
|
||||
# TODO twitter provides all sorts of extra info, like website/bio etc.
|
||||
# it may be worth considering pulling some of it in.
|
||||
def after_authenticate(auth_token)
|
||||
|
||||
result = Auth::Result.new
|
||||
|
||||
data = auth_token[:info]
|
||||
|
||||
result.username = screen_name = data["nickname"]
|
||||
result.name = name = data["name"]
|
||||
twitter_user_id = auth_token["uid"]
|
||||
|
||||
result.extra_data = {
|
||||
twitter_user_id: twitter_user_id,
|
||||
twitter_screen_name: screen_name
|
||||
}
|
||||
|
||||
user_info = TwitterUserInfo.where(twitter_user_id: twitter_user_id).first
|
||||
|
||||
result.user = user_info.try(:user)
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def after_create_account(user, auth)
|
||||
data = auth[:extra_data]
|
||||
TwitterUserInfo.create(
|
||||
user_id: user.id,
|
||||
screen_name: data[:twitter_screen_name],
|
||||
twitter_user_id: data[:twitter_user_id]
|
||||
)
|
||||
end
|
||||
|
||||
end
|
Reference in New Issue
Block a user