Class: PuavoRest::SSO

Inherits:
PuavoSinatra show all
Defined in:
resources/sso.rb

Constant Summary

Constant Summary

Constants inherited from PuavoSinatra

PuavoSinatra::ROOT

Instance Method Summary (collapse)

Methods inherited from PuavoSinatra

#auth, #basic_auth, #flog, #flog=, #from_post, #json_params, #kerberos, #legacy_server_auth, #limit, #pw_mgmt_server_auth, #server_auth, #txt

Instance Method Details

- (Object) ensure_topdomain(org)



262
263
264
265
266
267
268
# File 'resources/sso.rb', line 262

def ensure_topdomain(org)
  return if org.nil?
  if !org.end_with?(topdomain)
    return "#{ org }.#{ topdomain }"
  end
  org
end

- (Object) fetch_external_service



113
114
115
# File 'resources/sso.rb', line 113

def fetch_external_service
  ExternalService.by_url(params["return_to"]) if params["return_to"]
end

- (Boolean) handheld?

Returns:

  • (Boolean)


192
193
194
# File 'resources/sso.rb', line 192

def handheld?
  browser.ios? || browser.android? || browser.nokia? || browser.rim?
end

- (Boolean) invalid_credentials?

Returns:

  • (Boolean)


188
189
190
# File 'resources/sso.rb', line 188

def invalid_credentials?
  env["REQUEST_METHOD"] == "POST" && !params["password"].to_s.empty?
end

- (Object) preferred_organisation



270
271
272
273
274
275
276
277
278
279
# File 'resources/sso.rb', line 270

def preferred_organisation
  [
    params["organisation"],
    request.host,
  ].compact.map do |org|
    ensure_topdomain(org)
  end.map do |org|
    Organisation.by_domain(org)
  end.first
end

- (Object) render_form(error_message, err = nil)



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'resources/sso.rb', line 196

def render_form(error_message, err=nil)
  if env["REQUEST_METHOD"] == "POST"
    @error_message = error_message
    err_msg = {
      :login_ok => false,
      :reason => error_message,
      :params => params
    }
    if err
      err_msg[:error_class] = err.class.name
      err_msg[:error_message] = err.message
      err_msg[:meta] = err.meta
      err_msg[:organisation_domain] = Organisation.current.domain
    end
    flog.warn "sso", err_msg
  end

  @external_service ||= fetch_external_service
  @organisation = preferred_organisation

  if !(browser.linux? && browser.gecko?)
    # Kerberos authentication works only on Opinsys desktops with Firefox.
    # Disable authentication negotiation on others since it  may cause
    # unwanted basic auth popups (at least Chrome & IE @ Windows).
    response.headers.delete("WWW-Authenticate")
  end

  @login_content = {
    "opinsys_logo_url" => "/v3/img/opinsys_logo.png",
    "external_service_name" =>  @external_service["name"],
    "return_to" => params["return_to"],
    "organisation" => @organisation,
    "username_placeholder" => username_placeholder,
    "username" => params["username"],
    "invalid_credentials?" => invalid_credentials?,
    "handheld?" => handheld?,
    "error_message" => @error_message,
    "topdomain" => topdomain,
    "login_helper_js_url" => "/v3/scripts/login_helpers.js",
    "text_password" => t.sso.password,
    "text_login" => t.sso.,
    "text_help" => t.sso.help,
    "text_username_help" => t.sso.username_help,
    "text_organisation_help" => t.sso.organisation_help,
    "text_developers" => t.sso.developers,
    "text_developers_info" => t.sso.developers_info,
    "support_info" => t.sso.support_info,
    "text_login_to" => t.sso.
  }

  halt 401, {'Content-Type' => 'text/html'}, erb(:login_form, :layout => :layout)
end

- (Object) respond_auth



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
# File 'resources/sso.rb', line 125

def respond_auth
  if return_to.nil?
    raise BadInput, :user => "return_to missing"
  end

  @external_service = fetch_external_service

  if @external_service.nil?
    raise Unauthorized,
      :user => "Unknown client service #{ return_to.host }"
  end

  begin
    auth :basic_auth, :from_post, :kerberos
  rescue KerberosError => err
    return render_form(t.sso.kerberos_error, err)
  rescue JSONError => err
    # Pass custom error headers to the response login page
    response.headers.merge!(err.headers)
    return render_form(t.sso.bad_username_or_pw, err)
  end

  user = User.current
  primary_school = user.school

  # Read organisation data manually instead of using the cached one because
  # enabled external services might be updated.
  organisation = LdapModel.setup(:credentials => CONFIG["server"]) do
    Organisation.by_dn(LdapModel.organisation["dn"])
  end

  school_allows = Array(primary_school["external_services"]).
    include?(@external_service["dn"])
  organisation_allows = Array(organisation["external_services"]).
    include?(@external_service["dn"])
  trusted = @external_service["trusted"]

  if not (trusted || school_allows || organisation_allows)
    return render_form(t.sso.service_not_activated)
  end


  url = @external_service.(user, return_to)
  logger.info "Redirecting SSO auth #{ user["first_name"] } #{ user["last_name"] } (#{ user["dn"] } to #{ url }"

  flog.info("sso login ok", {
    :return_to => return_to,
    :external_service => @external_service.to_hash,
    :user => user
  })

  flog.info("sso", {
    :login_ok => true,
    :return_to => return_to
  })

  redirect url
end

- (Object) return_to



109
110
111
# File 'resources/sso.rb', line 109

def return_to
  Addressable::URI.parse(params["return_to"]) if params["return_to"]
end

- (Object) topdomain



258
259
260
# File 'resources/sso.rb', line 258

def topdomain
  CONFIG["topdomain"]
end

- (Object) username_placeholder



117
118
119
120
121
122
123
# File 'resources/sso.rb', line 117

def username_placeholder
  if preferred_organisation
    t.sso.username
  else
    "#{ t.sso.username }@#{ t.sso.organisation }.#{ topdomain }"
  end
end

- (Object) username_prefill



249
250
251
252
253
254
255
256
# File 'resources/sso.rb', line 249

def username_prefill
  [
    # what user typed last
    params["username"],
    # organisation presetting
    (@organisation ? "@#{ @organisation["domain"] }" : nil),
  ].compact.first
end