class DiscourseApi::SingleSignOn

Constants

ACCESSORS
ARRAYS
BOOLS
FIXNUMS

Attributes

custom_fields[W]
sso_secret[W]
sso_url[W]

Public Class Methods

parse(payload, sso_secret = nil) click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 96
def self.parse(payload, sso_secret = nil)
  sso = new
  sso.sso_secret = sso_secret if sso_secret

  parsed = Rack::Utils.parse_query(payload)
  if sso.sign(parsed["sso"]) != parsed["sig"]
    diags =
      "\n\nsso: #{parsed["sso"]}\n\nsig: #{parsed["sig"]}\n\nexpected sig: #{sso.sign(parsed["sso"])}"
    if parsed["sso"] =~ %r{[^a-zA-Z0-9=\r\n/+]}m
      raise ParseError,
            "The SSO field should be Base64 encoded, using only A-Z, a-z, 0-9, +, /, and = characters. Your input contains characters we don't understand as Base64, see http://en.wikipedia.org/wiki/Base64 #{diags}"
    else
      raise ParseError, "Bad signature for payload #{diags}"
    end
  end

  decoded = Base64.decode64(parsed["sso"])
  decoded_hash = Rack::Utils.parse_query(decoded)

  ACCESSORS.each do |k|
    val = decoded_hash[k.to_s]
    val = val.to_i if FIXNUMS.include? k
    val = %w[true false].include?(val) ? val == "true" : nil if BOOLS.include? k
    val = val.split(",") if ARRAYS.include?(k) && !val.nil?
    sso.send("#{k}=", val)
  end

  decoded_hash.each do |k, v|
    if field = k[/^custom\.(.+)$/, 1]
      sso.custom_fields[field] = v
    end
  end

  sso
end
parse_hash(payload) click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 67
def self.parse_hash(payload)
  sso = new

  sso.sso_secret = payload.delete(:sso_secret)
  sso.sso_url = payload.delete(:sso_url)

  ACCESSORS.each do |k|
    val = payload[k]

    val = val.to_i if FIXNUMS.include? k
    val = %w[true false].include?(val) ? val == "true" : nil if BOOLS.include? k
    val = val.split(",") if ARRAYS.include?(k) && !val.nil?
    sso.send("#{k}=", val)
  end

  # Set custom_fields
  sso.custom_fields = payload[:custom_fields]

  # Add custom_fields (old format)
  payload.each do |k, v|
    if field = k[/^custom\.(.+)$/, 1]
      # Maintain adding of .custom bug
      sso.custom_fields["custom.#{field}"] = v
    end
  end

  sso
end
sso_secret() click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 59
def self.sso_secret
  raise MissingConfigError, "sso_secret not implemented on class, be sure to set it on instance"
end
sso_url() click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 63
def self.sso_url
  raise MissingConfigError, "sso_url not implemented on class, be sure to set it on instance"
end

Public Instance Methods

custom_fields() click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 144
def custom_fields
  @custom_fields ||= {}
end
diagnostics() click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 132
def diagnostics
  DiscourseApi::SingleSignOn::ACCESSORS.map { |a| "#{a}: #{send(a)}" }.join("\n")
end
payload() click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 157
def payload
  payload = Base64.strict_encode64(unsigned_payload)
  "sso=#{CGI.escape(payload)}&sig=#{sign(payload)}"
end
sign(payload) click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 148
def sign(payload)
  OpenSSL::HMAC.hexdigest("sha256", sso_secret, payload)
end
sso_secret() click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 136
def sso_secret
  @sso_secret || self.class.sso_secret
end
sso_url() click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 140
def sso_url
  @sso_url || self.class.sso_url
end
to_url(base_url = nil) click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 152
def to_url(base_url = nil)
  base = "#{base_url || sso_url}"
  "#{base}#{base.include?("?") ? "&" : "?"}#{payload}"
end
unsigned_payload() click to toggle source
# File lib/discourse_api/single_sign_on.rb, line 162
def unsigned_payload
  payload = {}

  ACCESSORS.each do |k|
    next if (val = send k) == nil
    payload[k] = val
  end

  @custom_fields.each { |k, v| payload["custom.#{k}"] = v.to_s } if @custom_fields

  Rack::Utils.build_query(payload)
end