Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/controllers/ajax_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
class AjaxController < ::ScopeController
include Rescue

authentication_required domain: lambda { |c|
api_authentication_required domain: lambda { |c|
c.instance_variable_get(:@scoped_domain_id)
},
domain_name: lambda { |c|
Expand Down
269 changes: 56 additions & 213 deletions app/controllers/dashboard_controller.rb
Original file line number Diff line number Diff line change
@@ -1,139 +1,25 @@
# frozen_string_literal: true

# This class guarantees that the user is logged in and his token is rescoped.
# All subclasses which require a logged in user should inherit from this class.
class DashboardController < ::ScopeController
include UrlHelper
include AvatarHelper
include Rescue
prepend_before_action :define_after_login_url

prepend_before_action do
requested_url = request.env['REQUEST_URI']
referer_url = request.referer
referer_url =
begin
"#{URI(referer_url).path}?#{URI(referer_url).query}"
rescue StandardError
nil
end
authentication_required(
domain: lambda { |c| c.instance_variable_get(:@scoped_domain_id)},
domain_name: lambda { |c| c.instance_variable_get(:@scoped_domain_name)},
project: lambda { |c| c.instance_variable_get(:@scoped_project_id)},
two_factor: :two_factor_required?
)

unless params[:after_login]
params[:after_login] = if requested_url =~ /(\?|&)modal=true/ &&
referer_url =~ /(\?|&)overlay=.+/
referer_url
else
requested_url
end
end
end

before_action :load_help_text

# authenticate user -> current_user is available
# throws only errors
# api_authentication_required domain: ->(c) { c.instance_variable_get(:@scoped_domain_id) },
# domain_name: ->(c) { c.instance_variable_get(:@scoped_domain_name) },
# project: ->(c) { c.instance_variable_get(:@scoped_project_id) },
# rescope: false,
# two_factor: :two_factor_required?,
# except: :terms_of_use

# with redirect
authentication_required domain: lambda { |c|
c.instance_variable_get(:@scoped_domain_id)
},
domain_name: lambda { |c|
c.instance_variable_get(:@scoped_domain_name)
},
project: lambda { |c|
c.instance_variable_get(:@scoped_project_id)
},
rescope: false,
two_factor: :two_factor_required?,
except: :terms_of_use

# after_login is used by monsoon_openstack_auth gem.
# After the authentication process has finished the
# after_login can be removed.
before_action { params.delete(:after_login) }

# check if user has accepted terms of use.
# Otherwise it is a new, unboarded user.
before_action :check_terms_of_use,
except: %i[accept_terms_of_use terms_of_use]
# rescope token
before_action :rescope_token, except: [:terms_of_use]
before_action { params.delete(:after_login) }
before_action :check_terms_of_use, except: %i[accept_terms_of_use terms_of_use]
before_action :raven_context, except: [:terms_of_use]
before_action :load_active_project,
:load_webcli_endpoint,
except: %i[terms_of_use]
before_action :set_mailer_host

# this method checks if user has permissions for the new scope and if so
# it rescopes the token.
def rescope_token
if @scoped_project_id
# @scoped_project_id exists -> check if friendly id for this project
# also exists. The scope controller runs bevore this controller and
# updates the friendlyId entry if project exists.
unless FriendlyIdEntry.find_project(@scoped_domain_id, @scoped_project_id)
# friendly id entry is nil -> reset @can_access_project, render project
# not found page and return.
@can_access_project = false
return render(template: 'application/exceptions/project_not_found')
end
before_action :load_active_project, except: %i[terms_of_use]
before_action :set_mailer_host, except: %i[terms_of_use]

# NOTE: LEAVE this here because for better review
# we do not need extra permissions check for project and domains because elektron and monsoon_openstack_auth
# are doing the job. If the user has no access with his token monsoon_openstack_auth will trow an NotAuthorized
# error that we will catch and handle to show 'application/exceptions/unauthorized'
#
# if no access this is handled in rescue from above
# did not return -> check if user projects include the requested project.
# has_project_access = services.identity.has_project_access(
# @scoped_project_id
# )

# unless has_project_access
# # user has no permissions for requested project -> reset
# # @can_access_project, render unauthorized page and return.
# @can_access_project = false
# return render(template: 'application/exceptions/unauthorized')
# end
elsif @scoped_domain_id
# NOTE: LEAVE hit here because for better review
# @scoped_project_id is nil and @scoped_domain_id exists -> check if
# user can access the requested domain.

# check if user has access to current domain, add rescue nil for cases where the token scope inexplicably contains a deleted project
# without the rescue this call leads to an error message and the user can't see the domain page
# has_domain_access = services.identity.has_domain_access(@scoped_domain_id) rescue nil

# unless has_domain_access
# # this can happen if the user is using a link to some domain and project
# # user has no permissions for the new domain -> rescope to
# # unscoped token and return this will be the startpoint to rescope again
# return authentication_rescope_token(domain: nil, project: nil)
# end
else
# both @scoped_project_id and @scoped_domain_id are nil
# -> render unauthorized page and return.
@can_access_project = false
return render(template: 'application/exceptions/unauthorized')
end
# did not return yet -> rescope token to the 'new' scope.
begin
authentication_rescope_token
rescue MonsoonOpenstackAuth::Authentication::NotAuthorized => e
if e.message =~ /has no access to the requested scope/
if @scoped_project_id.present?
render(template: 'application/exceptions/unauthorized')
elsif @scoped_domain_id.present?
authentication_rescope_token(domain: nil, project: nil)
end
end
# All other NotAuthorized Errors handled by "rescue_and_render_exception_page"
end
# In your Rescue module (application_controller.rb or concern)
rescue_from MonsoonOpenstackAuth::Authentication::NotAuthorized do |exception|
render template: 'application/exceptions/unauthorized', status: :unauthorized
end

def check_terms_of_use
Expand All @@ -159,8 +45,6 @@ def accept_terms_of_use
tou_version: Settings.send(@domain_config&.terms_of_use_name).version,
domain_id: current_user.user_domain_id
)

reset_last_request_cache
# redirect to original path, this is the case after the TOU view
if params[:orginal_url]
redirect_to params[:orginal_url]
Expand All @@ -186,25 +70,51 @@ def terms_of_use
render action: :terms_of_use
end

def two_factor_required?
if ENV['TWO_FACTOR_AUTH_DOMAINS']
@two_factor_required =
ENV['TWO_FACTOR_AUTH_DOMAINS']
.gsub(/\s+/, '')
.split(',')
.include?(@scoped_domain_name)
return @two_factor_required
end
false
private

def load_active_project
return unless @scoped_project_id

@active_project ||=
services.identity.find_project(
@scoped_project_id,
subtree_as_ids: true,
parents_as_ids: true
)
end

protected
def define_after_login_url
requested_url = request.env['REQUEST_URI']
referer_url = request.referer
referer_url =
begin
"#{URI(referer_url).path}?#{URI(referer_url).query}"
rescue StandardError
nil
end

unless params[:after_login]
params[:after_login] = if requested_url =~ /(\?|&)modal=true/ &&
referer_url =~ /(\?|&)overlay=.+/
referer_url
else
requested_url
end
end
end

def show_beta?
params[:betafeatures] == 'showme'
def tou_accepted?
UserProfile.tou_accepted?(
current_user.id,
current_user.user_domain_id,
Settings.send(@domain_config&.terms_of_use_name).version
)
end

helper_method :show_beta?
def set_mailer_host
ActionMailer::Base.default_url_options[:host] = request.host_with_port
ActionMailer::Base.default_url_options[:protocol] = request.protocol
end

def raven_context
@sentry_user_context =
Expand Down Expand Up @@ -233,74 +143,7 @@ def raven_context
end
@sentry_tags_context = tags
Raven.tags_context(tags)
end

def load_active_project
return unless @scoped_project_id

# load active project. Try first from ObjectCache and then from API

cached_active_project = ObjectCache.where(id: @scoped_project_id).first
@active_project = if cached_active_project
Identity::Project.new(services.identity, cached_active_project.payload)
else
service_user.identity.find_project(@scoped_project_id)
end

return if @active_project && @active_project.name == @scoped_project_name

@active_project =
services.identity.find_project(
@scoped_project_id,
subtree_as_ids: true,
parents_as_ids: true
)
FriendlyIdEntry.update_project_entry(@active_project)
end

def load_webcli_endpoint
@webcli_endpoint = current_user.service_url('webcli')
end

def tou_accepted?
# Consider that every plugin controller inhertis from dashboard controller
# and check_terms_of_use method is called on every request.
# In order to reduce api calls we cache the result of new_user?
# in the session for 5 minutes.
is_cache_expired =
current_user.id != session[:last_user_id] ||
session[:last_request_timestamp].nil? ||
(session[:last_request_timestamp] < Time.now - 5.minute)
if is_cache_expired
session[:last_request_timestamp] = Time.now
session[:last_user_id] = current_user.id
session[:tou_accepted] = UserProfile.tou_accepted?(
current_user.id,
current_user.user_domain_id,
Settings.send(@domain_config&.terms_of_use_name).version
)
end

session[:tou_accepted]
end

def reset_last_request_cache
session[:last_request_timestamp] = nil
session[:last_user_id] = nil
end

def set_mailer_host
ActionMailer::Base.default_url_options[:host] = request.host_with_port
ActionMailer::Base.default_url_options[:protocol] = request.protocol
end

def project_id_required

return unless params[:project_id].blank?

raise Core::Error::ProjectNotFound,
'The project you have requested was not found.'
end
end

def load_help_text
# Different types of help files are supported:
Expand Down Expand Up @@ -372,4 +215,4 @@ def load_help_text
@plugin_help_links = @plugin_help_links.gsub('#{@sap_docu_url}', sap_url_for('documentation'))
end
end
end
end
14 changes: 4 additions & 10 deletions app/controllers/scope_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,15 @@ def hidden_plugin_redirect
def load_scoped_objects
# initialize scoped domain's and project's friendly id
# use existing, user's or default domain
domain_id =
params[:domain_id] || Rails.application.config.service_user_domain_name
domain_id = params[:domain_id] #|| Rails.application.config.service_user_domain_name
project_id = params[:project_id]

@scoped_domain_fid = @scoped_domain_id = domain_id
@scoped_project_fid = @scoped_project_id = project_id

# try to find or create friendly_id entry for domain
rescoping_service = Dashboard::RescopingService.new(service_user)
domain_friendly_id =
rescoping_service.domain_friendly_id(@scoped_domain_fid)
domain_friendly_id = rescoping_service.domain_friendly_id(@scoped_domain_fid)
raise Core::Error::DomainNotFound, "Domain #{domain_id} not found!" unless domain_friendly_id

# set scoped domain parameters
Expand All @@ -56,10 +54,6 @@ def load_scoped_objects
@scoped_project_name = project_friendly_id.name
end

# puts "SCOPED CONTROLLER"
# puts @scoped_domain_id
# puts @scoped_project_id

# url_for does not work for plugins. Use path instead!
if (domain_id != @scoped_domain_fid || project_id != @scoped_project_fid) && @scoped_domain_id
# replace domain_id with domain friendly id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -748,14 +748,6 @@ def hard_reset
execute_instance_action("reboot", "HARD")
end

def two_factor_required?
if action_name == "console"
true
else
super
end
end

def edit_securitygroups
@action_from_show = params[:action_from_show] == "true" || false
@instance = services.compute.find_server(params[:id])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,14 @@ def delete_with_prodel

private

def project_id_required

return unless params[:project_id].blank?

raise Core::Error::ProjectNotFound,
'The project you have requested was not found.'
end

def get_project
get_project_id
@project =
Expand Down
Loading
Loading