Skip to content

Commit

Permalink
Feature: Single sign-on (SSO).
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan Lue authored and thorsteneckel committed Sep 5, 2019
1 parent 0afb105 commit 33bef71
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 252 deletions.
2 changes: 1 addition & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base
include ApplicationController::HandlesTransitions
include ApplicationController::Authenticates
include ApplicationController::SetsHeaders
include ApplicationController::ChecksMaintainance
include ApplicationController::ChecksMaintenance
include ApplicationController::RendersModels
include ApplicationController::HasUser
include ApplicationController::HasResponseExtentions
Expand Down
45 changes: 26 additions & 19 deletions app/controllers/application_controller/authenticates.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,6 @@ def authentication_check_only(auth_param = {})
return authentication_check_prerequesits(user, 'session', auth_param) if user
end

# check sso based authentication
sso_user = User.sso(params)
if sso_user
if authentication_check_prerequesits(sso_user, 'session', auth_param)
session[:persistent] = true
return sso_user
end
end

# check http basic based authentication
authenticate_with_http_basic do |username, password|
request.session_options[:skip] = true # do not send a session cookie
Expand Down Expand Up @@ -135,21 +126,37 @@ def authentication_check_only(auth_param = {})
false
end

def authentication_check_prerequesits(user, auth_type, auth_param)
if check_maintenance_only(user)
raise Exceptions::NotAuthorized, 'Maintenance mode enabled!'
end
def authenticate_with_password
user = User.authenticate(params[:username], params[:password])
raise Exceptions::NotAuthorized, 'Wrong Username or Password combination.' if !user

raise Exceptions::NotAuthorized, 'User is inactive!' if !user.active
session.delete(:switched_from_user_id)
authentication_check_prerequesits(user, 'session', {})
end

# check scopes / permission check
if auth_param[:permission] && !user.permissions?(auth_param[:permission])
raise Exceptions::NotAuthorized, 'Not authorized (user)!'
end
def authenticate_with_sso
user = begin
login = request.env['REMOTE_USER'] ||
request.env['HTTP_REMOTE_USER'] ||
request.headers['X-Forwarded-User']

User.lookup(login: login&.downcase)
end

raise Exceptions::NotAuthorized, 'no valid session' if !user

session.delete(:switched_from_user_id)
authentication_check_prerequesits(user, 'session', {})
end

def authentication_check_prerequesits(user, auth_type, auth_param)
raise Exceptions::NotAuthorized, 'Maintenance mode enabled!' if in_maintenance_mode?(user)
raise Exceptions::NotAuthorized, 'User is inactive!' if !user.active
raise Exceptions::NotAuthorized, 'Not authorized (user)!' if auth_param[:permission] && !user.permissions?(auth_param[:permission])

current_user_set(user, auth_type)
user_device_log(user, auth_type)
logger.debug { "#{auth_type} for '#{user.login}'" }
true
user
end
end
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
module ApplicationController::ChecksMaintainance
module ApplicationController::ChecksMaintenance
extend ActiveSupport::Concern

private

def check_maintenance(user)
return false if !check_maintenance_only(user)

raise Exceptions::NotAuthorized, 'Maintenance mode enabled!'
end

# check maintenance mode
def check_maintenance_only(user)
def in_maintenance_mode?(user)
return false if Setting.get('maintenance_mode') != true
return false if user.permissions?('admin.maintenance')

Expand Down
148 changes: 22 additions & 126 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,112 +2,32 @@

class SessionsController < ApplicationController
prepend_before_action :authentication_check, only: %i[switch_to_user list delete]
skip_before_action :verify_csrf_token, only: %i[show destroy create_omniauth failure_omniauth create_sso]
skip_before_action :verify_csrf_token, only: %i[show destroy create_omniauth failure_omniauth]

# "Create" a login, aka "log the user in"
def create

# in case, remove switched_from_user_id
session[:switched_from_user_id] = nil

# authenticate user
user = User.authenticate(params[:username], params[:password])

# check maintenance mode
check_maintenance(user)

# auth failed
raise Exceptions::NotAuthorized, 'Wrong Username or Password combination.' if !user

# remember me - set session cookie to expire later
expire_after = nil
if params[:remember_me]
expire_after = 1.year
end
request.env['rack.session.options'][:expire_after] = expire_after

# set session user
current_user_set(user)

# log device
return if !user_device_log(user, 'session')

# log new session
user.activity_stream_log('session started', user.id, true)

# add session user assets
assets = {}
assets = user.assets(assets)

# auto population of default collections
collections, assets = SessionHelper.default_collections(user, assets)

# get models
models = SessionHelper.models(user)

# sessions created via this
# controller are persistent
session[:persistent] = true
user = authenticate_with_password
initiate_session_for(user)

# return new session data
render status: :created,
json: {
session: user,
config: config_frontend,
models: models,
collections: collections,
assets: assets,
}
render status: :created,
json: SessionHelper.json_hash(user).merge(config: config_frontend)
end

def show

user_id = nil

# no valid sessions
if session[:user_id]
user_id = session[:user_id]
end

if !user_id || !User.exists?(user_id)
# get models
models = SessionHelper.models()

render json: {
error: 'no valid session',
config: config_frontend,
models: models,
collections: {
Locale.to_app_model => Locale.where(active: true)
},
}
return
end

# Save the user ID in the session so it can be used in
# subsequent requests
user = User.find(user_id)

# log device
return if !user_device_log(user, 'session')

# add session user assets
assets = {}
assets = user.assets(assets)

# auto population of default collections
collections, assets = SessionHelper.default_collections(user, assets)

# get models
models = SessionHelper.models(user)
user = authentication_check_only || authenticate_with_sso
initiate_session_for(user)

# return current session
render json: SessionHelper.json_hash(user).merge(config: config_frontend)
rescue Exceptions::NotAuthorized => e
raise if e.message != 'no valid session'

render json: {
session: user,
error: e.message,
config: config_frontend,
models: models,
collections: collections,
assets: assets,
models: SessionHelper.models,
collections: { Locale.to_app_model => Locale.where(active: true) }
}
end

Expand Down Expand Up @@ -146,8 +66,7 @@ def create_omniauth
authorization = Authorization.create_from_hash(auth, current_user)
end

# check maintenance mode
if check_maintenance_only(authorization.user)
if in_maintenance_mode?(authorization.user)
redirect_to '/#'
return
end
Expand All @@ -169,36 +88,6 @@ def failure_omniauth
raise Exceptions::UnprocessableEntity, "Message from #{params[:strategy]}: #{params[:message]}"
end

def create_sso

# in case, remove switched_from_user_id
session[:switched_from_user_id] = nil

user = User.sso(params)

# Log the authorizing user in.
if user

# check maintenance mode
if check_maintenance_only(user)
redirect_to '/#'
return
end

# set current session user
current_user_set(user)

# log new session
user.activity_stream_log('session started', user.id, true)

# remember last login date
user.update_last_login
end

# redirect to app
redirect_to '/#'
end

# "switch" to user
def switch_to_user
permission_check(['admin.session', 'admin.user'])
Expand Down Expand Up @@ -308,6 +197,12 @@ def delete

private

def initiate_session_for(user)
request.env['rack.session.options'][:expire_after] = 1.year if params[:remember_me]
session[:persistent] = true
user.activity_stream_log('session started', user.id, true)
end

def config_frontend

# config
Expand All @@ -333,4 +228,5 @@ def config_frontend

config
end

end
21 changes: 0 additions & 21 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -333,27 +333,6 @@ def self.identify(identifier)

=begin
authenticate user again sso
result = User.sso(sso_params)
returns
result = user_model # user model if authentication was successfully
=end

def self.sso(params)

# try to login against configure auth backends
user_auth = Sso.check(params)
return if !user_auth

user_auth
end

=begin
create user from from omni auth hash
result = User.create_from_hash!(hash)
Expand Down
3 changes: 0 additions & 3 deletions config/routes/auth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
match '/auth/:provider/callback', to: 'sessions#create_omniauth', via: %i[post get puts delete]
match '/auth/failure', to: 'sessions#failure_omniauth', via: %i[post get]

# sso
match '/auth/sso', to: 'sessions#create_sso', via: %i[post get]

# sessions
match api_path + '/signin', to: 'sessions#create', via: :post
match api_path + '/signshow', to: 'sessions#show', via: %i[get post]
Expand Down
14 changes: 13 additions & 1 deletion lib/session_helper.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
module SessionHelper
def self.default_collections(user, assets = {})
def self.json_hash(user)
collections, assets = default_collections(user)

{
session: user,
models: models(user),
collections: collections,
assets: assets,
}
end

def self.default_collections(user)

# auto population collections, store all here
default_collection = {}
assets = user.assets({})

# load collections to deliver from external files
dir = File.expand_path('..', __dir__)
Expand Down
53 changes: 0 additions & 53 deletions lib/sso.rb

This file was deleted.

Loading

0 comments on commit 33bef71

Please sign in to comment.