This repository was archived by the owner on May 17, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathaccount_controller_patch.rb
194 lines (161 loc) · 6.62 KB
/
account_controller_patch.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
194
require_dependency 'account_controller'
module Redmine::OmniAuthSAML
module AccountControllerPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
alias_method_chain :login, :saml
alias_method_chain :logout, :saml
end
end
module InstanceMethods
def login_with_saml
#TODO: test 'replace_redmine_login' feature
if saml_settings["enabled"] && saml_settings["replace_redmine_login"]
redirect_to :controller => "account", :action => "login_with_saml_redirect", :provider => "saml", :origin => back_url
else
login_without_saml
end
end
def login_with_saml_redirect
render :text => "Not Found", :status => 404
end
def login_with_saml_callback
auth = request.env["omniauth.auth"]
#user = User.find_by_provider_and_uid(auth["provider"], auth["uid"])
user = User.find_or_create_from_omniauth(auth)
# taken from original AccountController
# maybe it should be splitted in core
if user.blank?
logger.warn "Failed login for '#{auth[:uid]}' from #{request.remote_ip} at #{Time.now.utc}"
error = l(:notice_account_invalid_creditentials).sub(/\.$/, '')
if saml_settings["enabled"]
link = self.class.helpers.link_to(l(:text_logout_from_saml), saml_logout_url(home_url), :target => "_blank")
error << ". #{l(:text_full_logout_proposal, :value => link)}"
end
if saml_settings["replace_redmine_login"]
render_error({:message => error.html_safe, :status => 403})
return false
else
flash[:error] = error
redirect_to signin_url
end
else
user.update_attribute(:last_login_on, Time.now)
params[:back_url] = request.env["omniauth.origin"] unless request.env["omniauth.origin"].blank?
successful_authentication(user)
#cannot be set earlier, because sucessful_authentication() triggers reset_session()
session[:logged_in_with_saml] = true
end
end
def login_with_saml_failure
error = params[:message] || 'unknown'
error = 'error_saml_' + error
if saml_settings["replace_redmine_login"]
render_error({:message => error.to_sym, :status => 500})
return false
else
flash[:error] = l(error.to_sym)
redirect_to signin_url
end
end
def logout_with_saml
if saml_settings["enabled"] && session[:logged_in_with_saml]
do_logout_with_saml
else
logout_without_saml
end
end
def do_logout_with_saml
# If we're given a logout request, handle it in the IdP logout initiated method
if params[:SAMLRequest]
idp_logout_request
# We've been given a response back from the IdP, process it
elsif params[:SAMLResponse]
process_logout_response
# Initiate SLO (send Logout Request)
else
sp_logout_request
end
end
# Method to handle IdP initiated logouts
def idp_logout_request
settings = OneLogin::RubySaml::Settings.new omniauth_saml_settings
logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest])
unless logout_request.is_valid?
logger.error 'IdP initiated LogoutRequest was not valid!'
render :inline => logger.error
return
end
logger.info "IdP initiated Logout for #{logout_request.name_id}"
# Actually log out this session
saml_logout_user
# Generate a response to the IdP.
logout_request_id = logout_request.id
logout_response = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, logout_request_id, nil, :RelayState => params[:RelayState])
redirect_to logout_response
end
# After sending an SP initiated LogoutRequest to the IdP, we need to accept
# the LogoutResponse, verify it, then actually delete our session.
def process_logout_response
settings = OneLogin::RubySaml::Settings.new omniauth_saml_settings
logout_response = OneLogin::RubySaml::Logoutresponse.new(params[:SAMLResponse], settings, session.has_key?(:transaction_id) ? { matches_request_id: session[:transaction_id] } : {})
logger.info "LogoutResponse is: #{logout_response.to_s}"
# Validate the SAML Logout Response
if not logout_response.validate
logger.error "The SAML Logout Response is invalid"
else
# Actually log out this session
if logout_response.success?
logger.info "Delete session for '#{User.current.login}'"
saml_logout_user
end
end
redirect_to home_path
end
# Create a SP initiated SLO
def sp_logout_request
# LogoutRequest accepts plain browser requests w/o parameters
settings = omniauth_saml_settings
if not settings[:signout_url]
logger.info "SLO IdP Endpoint not found in settings, executing then a normal logout'"
saml_logout_user
redirect_to home_path
else
# Since we created a new SAML request, save the transaction_id
# to compare it with the response we get back
logout_request = OneLogin::RubySaml::Logoutrequest.new
session[:transaction_id] = logout_request.uuid
logger.info "New SP SLO for userid '#{User.current.login}' transactionid '#{session[:transaction_id]}'"
settings[:name_identifier_value] ||= name_identifier_value
relay_state = home_url # url_for controller: 'saml', action: 'index'
redirect_to(logout_request.create(OneLogin::RubySaml::Settings.new(settings), :RelayState => relay_state))
end
end
private
def saml_logout_user
logout_user
reset_session
end
def name_identifier_value
User.current.send Redmine::OmniAuthSAML.configured_saml[:name_identifier_value].to_sym
end
def saml_settings
Redmine::OmniAuthSAML.settings_hash
end
def omniauth_saml_settings
Redmine::OmniAuthSAML.configured_saml
end
def saml_logout_url(service = nil)
logout_uri = Redmine::OmniAuthSAML.configured_saml[:signout_url]
logout_uri += service.to_s unless logout_uri.blank?
logout_uri || home_url
end
end
end
end
unless AccountController.included_modules.include? Redmine::OmniAuthSAML::AccountControllerPatch
AccountController.send(:include, Redmine::OmniAuthSAML::AccountControllerPatch)
AccountController.skip_before_filter :verify_authenticity_token, :only => [:login_with_saml_callback]
end