discourse/app/controllers/user_open_ids_controller.rb
2013-02-05 14:16:51 -05:00

192 lines
5.9 KiB
Ruby

require 'openid'
require 'openid/extensions/sreg'
require 'openid/extensions/ax'
require 'openid/store/filesystem'
require_dependency 'email'
class UserOpenIdsController < ApplicationController
layout false
# need to be able to call this
skip_before_filter :check_xhr
# must be done, cause we may trigger a POST
skip_before_filter :verify_authenticity_token, :only => :complete
def frame
if params[:provider] == 'google'
params[:user_open_id] = {url: "https://www.google.com/accounts/o8/id"}
end
if params[:provider] == 'yahoo'
params[:user_open_id] = {url: "https://me.yahoo.com"}
end
create
end
def destroy
@open_id = UserOpenId.find(params[:id])
if @open_id.user.id == current_user.id
@open_id.destroy
end
redirect_to current_user
end
def new
@open_id = UserOpenId.new
end
def create
url = params[:user_open_id]
begin
# validations
@open_id = UserOpenId.new(url)
open_id_request = openid_consumer.begin @open_id.url
return_to, realm = ['complete','index'].map {|a| url_for :action => a, :only_path => false}
add_ax_request(open_id_request)
add_sreg_request(open_id_request)
# immediate mode is not required
if open_id_request.send_redirect?(realm, return_to, false)
redirect_to open_id_request.redirect_url(realm, return_to, false)
else
logger.warn("send_redirect? returned false")
render :text, open_id_request.html_markup(realm, return_to, false, {'id' => 'openid_form'})
end
rescue => e
flash[:error] = "There seems to be something wrong with your open id url"
logger.warn("failed to load contact open id: " + e.to_s)
render :text => 'Something went wrong, we have been notified, try again soon'
end
end
def complete
current_url = url_for(:action => 'complete', :only_path => false)
parameters = params.reject{|k,v|request.path_parameters[k]}.reject{|k,v| k == 'action' || k == 'controller'}
open_id_response = openid_consumer.complete(parameters, current_url)
case open_id_response.status
when OpenID::Consumer::SUCCESS
data = {}
if params[:did_sreg]
data = get_sreg_response(open_id_response)
end
if params[:did_ax]
info = get_ax_response(open_id_response)
data.merge!(info)
end
trusted = open_id_response.endpoint.server_url =~ /^https:\/\/www.google.com\// ||
open_id_response.endpoint.server_url =~ /^https:\/\/me.yahoo.com\//
email = data[:email]
user_open_id = UserOpenId.where(url: open_id_response.display_identifier).first
if trusted && user_open_id.nil? && user = User.where(email: email).first
# we trust so do an email lookup
user_open_id = UserOpenId.create(url: open_id_response.display_identifier, user_id: user.id, email: email, active: true)
end
authenticated = !user_open_id.nil?
if authenticated
user = user_open_id.user
# If we have to approve users
if SiteSetting.must_approve_users? and !user.approved?
@data = {awaiting_approval: true}
else
log_on_user(user)
@data = {authenticated: true}
end
else
@data = {
email: email,
name: User.suggest_name(email),
username: User.suggest_username(email),
email_valid: trusted,
auth_provider: "Google"
}
session[:authentication] = {
email: @data[:email],
email_valid: @data[:email_valid],
openid_url: open_id_response.display_identifier
}
end
else
# note there are lots of failure reasons, we treat them all as failures
logger.warn("Verification #{open_id_response.display_identifier || "" }"\
" failed: #{open_id_response.status.to_s}" )
logger.warn(open_id_response.message)
flash[:error] = "Sorry, I seem to be having trouble confirming your open id account, please try again!"
render :text => "Apologies, something went wrong ... try again soon"
end
end
protected
def persist_session
if s = UserSession.find
s.remember_me = true
s.save
end
end
def openid_consumer
@openid_consumer ||= OpenID::Consumer.new(session,
OpenID::Store::Filesystem.new("#{Rails.root}/tmp/openid"))
end
def get_sreg_response(open_id_response)
data = {}
sreg_resp = OpenID::SReg::Response.from_success_response(open_id_response)
unless sreg_resp.empty?
data[:email] = sreg_resp.data['email']
data[:nickname] = sreg_resp.data['nickname']
end
data
end
def get_ax_response(open_id_response)
data = {}
ax_resp = OpenID::AX::FetchResponse.from_success_response(open_id_response)
if ax_resp && !ax_resp.data.empty?
data[:email] = ax_resp.data['http://schema.openid.net/contact/email'][0]
end
data
end
def add_sreg_request(open_id_request)
sreg_request = OpenID::SReg::Request.new
sreg_request.request_fields(['email'], true)
# optional
sreg_request.request_fields(['dob', 'fullname', 'nickname'], false)
open_id_request.add_extension(sreg_request)
open_id_request.return_to_args['did_sreg'] = 'y'
end
def add_ax_request(open_id_request)
ax_request = OpenID::AX::FetchRequest.new
requested_attrs = [
['namePerson', 'fullname'],
['namePerson/friendly', 'nickname'],
['contact/email', 'email', true],
['contact/web/default', 'web_default'],
['birthDate', 'dob'],
['contact/country/home', 'country']
]
requested_attrs.each {|a| ax_request.add(OpenID::AX::AttrInfo.new("http://schema.openid.net/#{a[0]}", a[1], a[2] || false))}
open_id_request.add_extension(ax_request)
open_id_request.return_to_args['did_ax'] = 'y'
end
end