class Authie::Session

Attributes

controller[RW]
temporary_token[RW]

Public Class Methods

cleanup() click to toggle source

Cleanup any old sessions.

# File lib/authie/session.rb, line 307
def self.cleanup
  Authie.config.events.dispatch(:before_cleanup)
  # Invalidate transient sessions that haven't been used
  active.where('expires_at IS NULL AND last_activity_at < ?',
               Authie.config.session_inactivity_timeout.ago).each(&:invalidate!)
  # Invalidate persistent sessions that have expired
  active.where('expires_at IS NOT NULL AND expires_at < ?', Time.now).each(&:invalidate!)
  Authie.config.events.dispatch(:after_cleanup)
  true
end
convert_tokens_to_hashes() click to toggle source

Convert all existing active sessions to store their tokens in the database

# File lib/authie/session.rb, line 324
def self.convert_tokens_to_hashes
  active.where(token_hash: nil).where('token is not null').each do |s|
    hash = hash_token(s.token)
    where(id: s.id).update_all(token_hash: hash, token: nil)
  end
end
find_session_by_token(token) click to toggle source

Find a session by a token (either from a hash or from the raw token)

# File lib/authie/session.rb, line 281
def self.find_session_by_token(token)
  return nil if token.blank?

  active.where('token = ? OR token_hash = ?', token, hash_token(token)).first
end
get_session(controller) click to toggle source

Find a session from the database for the given controller instance. Returns a session object or :none if no session is found.

# File lib/authie/session.rb, line 269
def self.get_session(controller)
  cookies = controller.send(:cookies)
  if cookies[:user_session] && (session = find_session_by_token(cookies[:user_session]))
    session.temporary_token = cookies[:user_session]
    session.controller = controller
    session
  else
    :none
  end
end
hash_token(token) click to toggle source

Return a hash of a given token

# File lib/authie/session.rb, line 319
def self.hash_token(token)
  Digest::SHA256.hexdigest(token)
end
start(controller, params = {}) click to toggle source

Create a new session and return the newly created session object. Any other sessions for the browser will be invalidated.

# File lib/authie/session.rb, line 289
def self.start(controller, params = {})
  cookies = controller.send(:cookies)
  active.where(browser_id: cookies[:browser_id]).each(&:invalidate!)
  user_object = params.delete(:user)

  session = new(params)
  session.user = user_object
  session.controller = controller
  session.browser_id = cookies[:browser_id]
  session.login_at = Time.now
  session.login_ip = controller.request.ip
  session.host = controller.request.host
  session.save!
  Authie.config.events.dispatch(:start_session, session)
  session
end

Public Instance Methods

activate!() click to toggle source

Activate an old session

# File lib/authie/session.rb, line 179
def activate!
  self.active = true
  save!
end
check_security!() click to toggle source

Check the security of the session to ensure it can be used.

# File lib/authie/session.rb, line 116
def check_security!
  raise Authie::Error, 'Cannot check security without a controller' unless controller

  if cookies[:browser_id] != browser_id
    invalidate!
    Authie.config.events.dispatch(:browser_id_mismatch_error, self)
    raise BrowserMismatch, 'Browser ID mismatch'
  end

  unless active?
    invalidate!
    Authie.config.events.dispatch(:invalid_session_error, self)
    raise InactiveSession, 'Session is no longer active'
  end

  if expired?
    invalidate!
    Authie.config.events.dispatch(:expired_session_error, self)
    raise ExpiredSession, 'Persistent session has expired'
  end

  if inactive?
    invalidate!
    Authie.config.events.dispatch(:inactive_session_error, self)
    raise InactiveSession, 'Non-persistent session has expired'
  end

  if host && host != controller.request.host
    invalidate!
    Authie.config.events.dispatch(:host_mismatch_error, self)
    raise HostMismatch, "Session was created on #{host} but accessed using #{controller.request.host}"
  end

  true
end
expired?() click to toggle source

Has this persistent session expired?

# File lib/authie/session.rb, line 153
def expired?
  expires_at &&
    expires_at < Time.now
end
first_session_for_browser?() click to toggle source

Is this the first session for this session's browser?

# File lib/authie/session.rb, line 258
def first_session_for_browser?
  self.class.where('id < ?', id).for_user(user).where(browser_id: browser_id).empty?
end
first_session_for_ip?() click to toggle source

Is this the first session for the IP?

# File lib/authie/session.rb, line 263
def first_session_for_ip?
  self.class.where('id < ?', id).for_user(user).where(login_ip: login_ip).empty?
end
get(key) click to toggle source

Get some additional data from this session

# File lib/authie/session.rb, line 201
def get(key)
  (self.data ||= {})[key.to_s]
end
impersonate!(user) click to toggle source

Create a new session for impersonating for the given user

# File lib/authie/session.rb, line 238
def impersonate!(user)
  set_parent_cookie!
  self.class.start(controller, user: user, parent: self)
end
inactive?() click to toggle source

Has a non-persistent session become inactive?

# File lib/authie/session.rb, line 159
def inactive?
  expires_at.nil? &&
    last_activity_at &&
    last_activity_at < Authie.config.session_inactivity_timeout.ago
end
invalidate!() click to toggle source

Mark this session as invalid

# File lib/authie/session.rb, line 185
def invalidate!
  self.active = false
  save!
  cookies.delete(:user_session) if controller
  Authie.config.events.dispatch(:session_invalidated, self)
  true
end
invalidate_others!() click to toggle source

Invalidate all sessions but this one for this user

# File lib/authie/session.rb, line 206
def invalidate_others!
  self.class.where('id != ?', id).for_user(user).each(&:invalidate!)
end
mark_as_two_factored!() click to toggle source

Mark this request as two factor authoritsed

# File lib/authie/session.rb, line 229
def mark_as_two_factored!
  self.two_factored_at = Time.now
  self.two_factored_ip = controller.request.ip
  save!
  Authie.config.events.dispatch(:marked_as_two_factored, self)
  true
end
persist!() click to toggle source

Allow this session to persist rather than expiring at the end of the current browser session

# File lib/authie/session.rb, line 167
def persist!
  self.expires_at = Authie.config.persistent_session_length.from_now
  save!
  set_cookie!
end
persistent?() click to toggle source

Is this a persistent session?

# File lib/authie/session.rb, line 174
def persistent?
  !!expires_at
end
recently_seen_password?() click to toggle source

Have we seen the user's password recently in this sesion?

# File lib/authie/session.rb, line 219
def recently_seen_password?
  !!(password_seen_at && password_seen_at >= Authie.config.sudo_session_timeout.ago)
end
revert_to_parent!() click to toggle source

Revert back to the parent session

# File lib/authie/session.rb, line 244
def revert_to_parent!
  unless parent && cookies[:parent_user_session]
    raise NoParentSessionForRevert, 'Session does not have a parent therefore cannot be reverted.'
  end

  invalidate!
  parent.activate!
  parent.controller = controller
  parent.set_cookie!(cookies[:parent_user_session])
  cookies.delete(:parent_user_session)
  parent
end
see_password!() click to toggle source

Note that we have just seen the user enter their password.

# File lib/authie/session.rb, line 211
def see_password!
  self.password_seen_at = Time.now
  save!
  Authie.config.events.dispatch(:seen_password, self)
  true
end
set(key, value) click to toggle source

Set some additional data in this session

# File lib/authie/session.rb, line 194
def set(key, value)
  self.data ||= {}
  self.data[key.to_s] = value
  save!
end
touch!() click to toggle source

This method should be called each time a user performs an action while authenticated with this session.

# File lib/authie/session.rb, line 78
def touch!
  check_security!
  self.last_activity_at = Time.now
  self.last_activity_ip = controller.request.ip
  self.last_activity_path = controller.request.path
  self.requests += 1
  save!
  Authie.config.events.dispatch(:session_touched, self)
  true
end
two_factored?() click to toggle source

Is two factor authentication required for this request?

# File lib/authie/session.rb, line 224
def two_factored?
  !!(two_factored_at || parent_id)
end
user() click to toggle source

Return the user that

# File lib/authie/session.rb, line 58
def user
  return unless user_id && user_type

  @user ||= user_type.constantize.find_by(id: user_id) || :none
  @user == :none ? nil : @user
end
user=(user) click to toggle source

Set the user

# File lib/authie/session.rb, line 66
def user=(user)
  if user
    self.user_type = user.class.name
    self.user_id = user.id
  else
    self.user_type = nil
    self.user_id = nil
  end
end

Private Instance Methods

cookies() click to toggle source

Return all cookies on the associated controller

# File lib/authie/session.rb, line 334
def cookies
  controller.send(:cookies)
end