-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathplugin.rb
193 lines (156 loc) · 6.23 KB
/
plugin.rb
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# name: discourse-saml
# about: SAML Auth Provider
# version: 0.1
# author: Robin Ward
#require_dependency 'auth/oauth2_authenticator'
gem 'macaddr', '1.7.2'
gem 'uuid', '2.3.9'
gem 'ruby-saml', '1.17.0'
gem "omniauth-saml", '2.2.1'
gem "systemu", '2.6.5'
#gem 'saml2ruby', '1.1.0'
request_method = GlobalSetting.try(:saml_request_method) || 'get'
class SamlAuthenticator
def register_middleware(omniauth)
omniauth.provider :saml,
:name => 'saml',
:issuer => Discourse.base_url,
:idp_sso_target_url => GlobalSetting.saml_target_url,
:idp_cert_fingerprint => GlobalSetting.try(:saml_cert_fingerprint),
:idp_cert => GlobalSetting.try(:saml_cert),
:attribute_statements => { :nickname => ['screenName'] },
:assertion_consumer_service_url => Discourse.base_url + "/auth/saml/callback",
:custom_url => (GlobalSetting.try(:saml_request_method) == 'post') ? "/discourse_saml" : nil
end
def enabled?
return true
end
def after_authenticate(auth)
Rails.logger.info 'after authenticate'
result = Auth::Result.new
if GlobalSetting.try(:saml_log_auth)
::PluginStore.set("saml", "saml_last_auth", auth.inspect)
::PluginStore.set("saml", "saml_last_auth_raw_info", auth.extra[:raw_info].inspect)
::PluginStore.set("saml", "saml_last_auth_extra", auth.extra.inspect)
end
uid = auth[:uid]
result.name = auth[:info].name || uid
result.username = uid
if auth.extra.present? && auth.extra[:raw_info].present?
result.username = auth.extra[:raw_info].attributes['screenName'].try(:first) || uid
end
if GlobalSetting.try(:saml_use_uid) && auth.extra.present? && auth.extra[:raw_info].present?
result.username = auth.extra[:raw_info].attributes['uid'].try(:first) || uid
end
result.email = auth[:info].email || uid
result.email_valid = true
result.skip_email_validation = true
result.user = User.where(username: result.username).first ||
User.new(
username: result.username,
name: result.name,
email: result.email,
admin: false,
active: true,
approved: true
).tap(&:save!)
current_info = ::PluginStore.get("saml", "saml_user_#{uid}")
if current_info
result.user = User.where(id: current_info[:user_id]).first
end
result.user ||= User.where(email: Email.downcase(result.email)).first
if GlobalSetting.try(:saml_clear_username) && result.user.blank?
result.username = ''
end
result.extra_data = { saml_user_id: uid }
groups = auth.extra[:raw_info].attributes['role']
if(result.user)
update_user_groups(result.user, groups)
end
result
end
def after_create_account(user, auth)
groups = auth.extra[:raw_info].attributes['role']
::PluginStore.set("saml", "saml_user_#{auth[:extra_data][:saml_user_id]}", {user_id: user.id })
update_user_groups(user, groups)
end
def update_user_groups(user, groups)
Rails.logger.info 'update user groups'
Group.joins(:users).where(users: { id: user.id } ).each do |c|
gname = c.name
if groups.include?(gname)
groups.delete(gname) # remove it from the list
else
c.group_users.where(user_id: user.id).destroy_all
Rails.logger.info "Would remove group " + c.name
end
end
groups.each do |c|
grp = Group.where(name: c).first
if not grp.nil?
grp.group_users.create(user_id: user.id, group_id: grp.id)
Rails.logger.info "adding user to " + grp.name
end
end
if groups.include?('discourse-moderators')
user.moderator = true
user.save
else
user.moderator = false
user.save
end
if groups.include?('discourse-admins')
user.admin = true
user.save
else
user.admin = false
user.save
end
end
end
if request_method == 'post'
after_initialize do
module ::DiscourseSaml
class Engine < ::Rails::Engine
engine_name "discourse_saml"
isolate_namespace DiscourseSaml
end
end
class DiscourseSaml::DiscourseSamlController < ::ApplicationController
skip_before_filter :check_xhr
def index
authn_request = OneLogin::RubySaml::Authrequest.new
metadata_url = GlobalSetting.try(:saml_metadata_url)
settings = nil
if metadata_url
idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
settings = idp_metadata_parser.parse_remote(metadata_url)
settings.idp_sso_target_url = GlobalSetting.saml_target_url
settings.idp_cert ||= GlobalSetting.try(:saml_cert)
else
settings = OneLogin::RubySaml::Settings.new(:idp_sso_target_url => GlobalSetting.saml_target_url,
:idp_cert_fingerprint => GlobalSetting.try(:saml_cert_fingerprint),
:idp_cert => GlobalSetting.try(:saml_cert))
end
settings.compress_request = false
settings.passive = false
settings.issuer = Discourse.base_url
settings.assertion_consumer_service_url = Discourse.base_url + "/auth/saml/callback"
settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:protocol"
saml_params = authn_request.create_params(settings, {})
@saml_req = saml_params['SAMLRequest']
end
end
DiscourseSaml::Engine.routes.draw do
get '/' => 'discourse_saml#index'
end
Discourse::Application.routes.append do
mount ::DiscourseSaml::Engine, at: "/discourse_saml"
end
end
end
title = GlobalSetting.try(:saml_title) || "SAML"
button_title = GlobalSetting.try(:saml_button_title) || GlobalSetting.try(:saml_title) || "with SAML"
auth_provider :title => button_title,
:authenticator => SamlAuthenticator.new(),
:custom_url => request_method == 'post' ? "/discourse_saml" : nil