publiclab/spectral-workbench

View on GitHub
app/controllers/sessions_controller.rb

Summary

Maintainability
B
6 hrs
Test Coverage
# frozen_string_literal: true

require 'uri'

class SessionsController < ApplicationController
  @@openid_url_base = 'https://publiclab.org/people/'
  @@openid_url_suffix = '/identity'

  def login
    if logged_in?
      redirect_to '/'
    else
      @referer = params[:back_to]
    end
  end

  def new
    back_to = params[:back_to]
    # we pass a temp username; it'll be overwritten by the real one in PublicLab.org's response:
    open_id = 'x'
    openid_url = URI.decode(open_id)
    # here it is localhost:3000/people/admin/identity for admin
    # possibly user is providing the whole URL
    if openid_url.include? 'publiclab'
      if openid_url.include? 'http'
        # params[:subaction] contains the value of the provider
        # provider implies ['github', 'google_oauth2', 'twitter', 'facebook']
        url = if params[:subaction]
                # provider based authentication
                openid_url + '/' + params[:subaction]
              else
                # form based authentication
                openid_url
              end
      end
    else
      url = if params[:subaction]
              # provider based authentication
              @@openid_url_base + openid_url + @@openid_url_suffix + '/' + params[:subaction]
            else
              # form based authentication
              @@openid_url_base + openid_url + @@openid_url_suffix
            end
    end
    openid_authentication(url, back_to)
  end

  def failed_login(message = 'Authentication failed.')
    flash[:danger] = message
    redirect_to '/'
  end

  def successful_login(back_to, id)
    session[:user_id] = @current_user.id
    flash[:success] = 'You have successfully logged in.'
    if id
      redirect_to '/sites/' + id.to_s + '/upload'
    else
      if back_to
        back_to = '/dashboard' if back_to == '/'
        redirect_to back_to
      else
        redirect_to '/sites'
      end
    end
  end

  def logout
    session[:user_id] = nil
    flash[:success] = 'You have successfully logged out.'
    redirect_to '/'
  end

  # only on local installations and during testing, to bypass OpenID; add "local: true" to config/config.yml
  def local
    if APP_CONFIG['local'] == true && @current_user = User.find_by_login(params[:login])
      successful_login '', nil
    else
      flash[:error] = 'Forbidden'
      redirect_to '/'
    end
  end

  protected

  def openid_authentication(openid_url, back_to)
    # puts openid_url
    authenticate_with_open_id(openid_url, required: %i(nickname email fullname)) do |result, identity_url, registration|
      dummy_identity_url = identity_url
      dummy_identity_url = dummy_identity_url.split('/')
      identity_url = dummy_identity_url[0..-2].join('/') if dummy_identity_url.include?('github') || dummy_identity_url.include?('google_oauth2') || dummy_identity_url.include?('facebook') || dummy_identity_url.include?('twitter')
      # we splice back in the real username from PublicLab.org's response
      identity_url = identity_url.split('/')[0..-2].join('/') + '/' + registration['nickname']
      if result.successful?
        @user = User.find_by_identity_url(identity_url)

        unless @user
          @user = User.new
          @user.login = registration['nickname']
          @user.email = registration['email']
          @user.identity_url = identity_url
          hash = registration['fullname'].split(':')
          @user.role = hash[1].split('=')[1]

          begin
            @user.save!
          rescue ActiveRecord::RecordInvalid => e
            puts e
            failed_login 'User can not be associated to local account. Probably the account already exists with different case!'
            return
          end
        end

        nonce = params[:n]
        if nonce
          tmp = Sitetmp.find_by nonce: nonce
          if tmp
            data = tmp.attributes
            data.delete('nonce')
            site = Site.new(data)
            site.save
            tmp.destroy
          end
        end
        @current_user = @user
        if site
          successful_login back_to, site.id
        else
          successful_login back_to, nil
        end
      else
        failed_login result.message
        return false
      end
    end
  end
end