external_user.rb
3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
require 'ostruct'
module ExternalUser
extend ActiveSupport::Concern
included do
attr_accessor :external_person_id
end
def external_person
ExternalPerson.where(id: self.external_person_id).first
end
def person_with_external
self.external_person || self.person_without_external
end
module ClassMethods
def webfinger_lookup(login, domain, environment)
if login && domain && environment.has_federated_network?(domain)
url = URI.parse('https://'+ domain +'/.well-known/webfinger?resource=acct:'+
login+'@'+Environment.default.federated_networks.find_by_url(domain))
req = Net::HTTP::Get.new(url.to_s)
res = Net::HTTP.start(url.host, url.port) { |http| http.request(req) }
JSON.parse(res.body)
else
nil
end
end
def build_request(uri)
request = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == "https" # enable SSL/TLS
request.use_ssl = true
#TODO There may be self-signed certificates that we would not be able
#to verify, so we'll not verify the ssl certificate for now. Since
#this requests will go only towards trusted federated networks the admin
#configured we consider this not to be a big deal. Nonetheless we may be
#able in the future to require/provide the CA Files on the federation
#process which would allow us to verify the certificate.
request.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
request
end
def external_login(login, password, domain)
# Call Noosfero /api/login
result = nil
response = nil
redirections_allowed = 3
location = 'http://' + domain + '/api/v1/login'
request_params = CGI.unescape({ login: login, password: password }.to_query)
begin
while redirections_allowed > 0 && (response.blank? || response.code == '301')
uri = URI.parse(location)
request = build_request(uri)
response = request.post(uri.to_s, request_params)
location = response.header['location']
redirections_allowed -= 1
end
result = response.code.to_i / 100 === 2 ? JSON.parse(response.body) : nil
rescue
# Could not make request
end
result
end
# Authenticates a user from an external social network
def external_authenticate(username, password, environment)
login, domain = username.split('@')
webfinger = User.webfinger_lookup(login, domain, environment)
if webfinger
user = User.external_login(login, password, domain)
if user
u = User.new
u.email = user['user']['email']
u.login = login
webfinger = OpenStruct.new(
identifier: webfinger['properties']['identifier'],
name: webfinger['titles']['name'],
created_at: webfinger['properties']['created_at'],
domain: domain,
email: user['user']['email']
)
u.external_person_id = ExternalPerson.get_or_create(webfinger).id
return u
end
end
nil
end
end
end