diff --git a/app/controllers/account_authorization_configs_controller.rb b/app/controllers/authentication_providers_controller.rb similarity index 97% rename from app/controllers/account_authorization_configs_controller.rb rename to app/controllers/authentication_providers_controller.rb index 42955fb060d..237d0685060 100644 --- a/app/controllers/account_authorization_configs_controller.rb +++ b/app/controllers/authentication_providers_controller.rb @@ -211,9 +211,9 @@ # } # } # -class AccountAuthorizationConfigsController < ApplicationController +class AuthenticationProvidersController < ApplicationController before_action :require_context, :require_root_account_management - include Api::V1::AccountAuthorizationConfig + include Api::V1::AuthenticationProvider # @API List authentication providers # Returns a paginated list of authentication providers @@ -228,7 +228,7 @@ class AccountAuthorizationConfigsController < ApplicationController if api_request? render json: aacs_json(@account.authentication_providers.active) else - @presenter = AccountAuthorizationConfigsPresenter.new(@account) + @presenter = AuthenticationProvidersPresenter.new(@account) end end @@ -649,7 +649,7 @@ class AccountAuthorizationConfigsController < ApplicationController end format.json do msg = "duplicate provider #{account_config.auth_type}" - render json: { errors: [ { message: msg } ] }, status: 422 + render json: { errors: [ { message: msg } ] }, status: 422 end end return @@ -662,7 +662,7 @@ class AccountAuthorizationConfigsController < ApplicationController flash[:error] = account_config.errors.full_messages redirect_to(account_authentication_providers_path(@account)) end - format.json { raise ActiveRecord::RecordInvalid.new(account_config) } + format.json { raise ActiveRecord::RecordInvalid, account_config } end return end @@ -715,7 +715,7 @@ class AccountAuthorizationConfigsController < ApplicationController flash[:error] = aac.errors.full_messages redirect_to(account_authentication_providers_path(@account)) end - format.json { raise ActiveRecord::RecordInvalid.new(aac) } + format.json { raise ActiveRecord::RecordInvalid, aac } end return end @@ -885,8 +885,8 @@ class AccountAuthorizationConfigsController < ApplicationController if results.empty? return render( - :json => {:errors => {:account => t(:account_required, 'must be LDAP-authenticated')}}, - :status_code => 400 + :json => {:errors => {:account => t(:account_required, 'must be LDAP-authenticated')}}, + :status_code => 400 ) end @@ -942,7 +942,7 @@ class AccountAuthorizationConfigsController < ApplicationController protected def filter_data(data) auth_type = data.delete(:auth_type) - klass = AccountAuthorizationConfig.find_sti_class(auth_type) + klass = AuthenticationProvider.find_sti_class(auth_type) federated_attributes = data[:federated_attributes] federated_attributes = {} if federated_attributes == "" federated_attributes = federated_attributes.to_unsafe_h if federated_attributes.is_a?(ActionController::Parameters) @@ -950,8 +950,8 @@ class AccountAuthorizationConfigsController < ApplicationController data[:federated_attributes] = federated_attributes if federated_attributes data[:auth_type] = auth_type if data[:auth_type] == 'ldap' - data[:auth_over_tls] = 'start_tls' unless data.has_key?(:auth_over_tls) - data[:auth_over_tls] = AccountAuthorizationConfig::LDAP.auth_over_tls_setting(data[:auth_over_tls]) + data[:auth_over_tls] = 'start_tls' unless data.key?(:auth_over_tls) + data[:auth_over_tls] = AuthenticationProvider::LDAP.auth_over_tls_setting(data[:auth_over_tls]) end data end @@ -970,8 +970,7 @@ class AccountAuthorizationConfigsController < ApplicationController def update_account_settings_from_hash(data) return if data.empty? data.each do |setting, value| - setting_val = value.present? ? value : nil - @account.public_send("#{setting}=".to_sym, setting_val) + @account.public_send("#{setting}=".to_sym, value.presence) end @account.save! end diff --git a/app/controllers/login/canvas_controller.rb b/app/controllers/login/canvas_controller.rb index 68a1ab30351..05cabc11863 100644 --- a/app/controllers/login/canvas_controller.rb +++ b/app/controllers/login/canvas_controller.rb @@ -144,7 +144,7 @@ class Login::CanvasController < ApplicationController def maybe_render_mobile_login(status = nil) if mobile_device? @login_handle_name = @domain_root_account.login_handle_name_with_inference - @login_handle_is_email = @login_handle_name == AccountAuthorizationConfig.default_login_handle_name + @login_handle_is_email = @login_handle_name == AuthenticationProvider.default_login_handle_name js_env( GOOGLE_ANALYTICS_KEY: Setting.get('google_analytics_key', nil), ) diff --git a/app/controllers/login/oauth2_controller.rb b/app/controllers/login/oauth2_controller.rb index c652b152330..3a3fbf01292 100644 --- a/app/controllers/login/oauth2_controller.rb +++ b/app/controllers/login/oauth2_controller.rb @@ -28,8 +28,8 @@ class Login::Oauth2Controller < Login::OauthBaseController def create return unless validate_request - @aac = AccountAuthorizationConfig.find(jwt['aac_id']) - raise ActiveRecord::RecordNotFound unless @aac.is_a?(AccountAuthorizationConfig::Oauth2) + @aac = AuthenticationProvider.find(jwt['aac_id']) + raise ActiveRecord::RecordNotFound unless @aac.is_a?(AuthenticationProvider::Oauth2) unique_id = nil provider_attributes = {} diff --git a/app/controllers/login/oauth_controller.rb b/app/controllers/login/oauth_controller.rb index 4c35062319f..6d043b277e9 100644 --- a/app/controllers/login/oauth_controller.rb +++ b/app/controllers/login/oauth_controller.rb @@ -35,7 +35,7 @@ class Login::OauthController < Login::OauthBaseController def create @aac = @domain_root_account.authentication_providers.active.find(params[:id]) - raise ActiveRecord::RecordNotFound unless @aac.is_a?(AccountAuthorizationConfig::Oauth) + raise ActiveRecord::RecordNotFound unless @aac.is_a?(AuthenticationProvider::Oauth) oauth_state = session.delete(:oauth) request_token = OAuth::RequestToken.new(@aac.consumer, diff --git a/app/controllers/login/saml_controller.rb b/app/controllers/login/saml_controller.rb index dee502af14e..a6153e5477c 100644 --- a/app/controllers/login/saml_controller.rb +++ b/app/controllers/login/saml_controller.rb @@ -399,7 +399,7 @@ class Login::SamlController < ApplicationController logout_current_user - private_key = AccountAuthorizationConfig::SAML.private_key + private_key = AuthenticationProvider::SAML.private_key private_key = nil if aac.sig_alg.nil? forward_url = SAML2::Bindings::HTTPRedirect.encode(logout_response, relay_state: relay_state, @@ -418,7 +418,7 @@ class Login::SamlController < ApplicationController # This needs to be publicly available since external SAML # servers need to be able to access it without being authenticated. # It is used to disclose our SAML configuration settings. - metadata = AccountAuthorizationConfig::SAML.sp_metadata_for_account(@domain_root_account, request.host_with_port) + metadata = AuthenticationProvider::SAML.sp_metadata_for_account(@domain_root_account, request.host_with_port) render xml: metadata.to_xml end diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb index 91320de3f3c..48c0bd9e3ac 100644 --- a/app/controllers/login_controller.rb +++ b/app/controllers/login_controller.rb @@ -100,7 +100,7 @@ class LoginController < ApplicationController if session[:login_aac] # The AAC could have been deleted since the user logged in - aac = AccountAuthorizationConfig.where(id: session[:login_aac]).first + aac = AuthenticationProvider.where(id: session[:login_aac]).first redirect = aac.try(:user_logout_redirect, self, @current_user) end diff --git a/app/jsx/authentication_providers/AuthTypePicker.js b/app/jsx/authentication_providers/AuthTypePicker.js index 93126e3f063..9f7c63f1fe4 100644 --- a/app/jsx/authentication_providers/AuthTypePicker.js +++ b/app/jsx/authentication_providers/AuthTypePicker.js @@ -18,7 +18,7 @@ import React from 'react' import PropTypes from 'prop-types' -import I18n from 'i18n!account_authorization_configs' +import I18n from 'i18n!authentication_providers' import Select from '@instructure/ui-core/lib/components/Select' class AuthTypePicker extends React.Component { diff --git a/app/jsx/bundles/account_authorization_configs.js b/app/jsx/bundles/authentication_providers.js similarity index 100% rename from app/jsx/bundles/account_authorization_configs.js rename to app/jsx/bundles/authentication_providers.js diff --git a/app/models/account.rb b/app/models/account.rb index d7bd4fb4f0f..4fe0ac51e59 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -64,8 +64,8 @@ class Account < ActiveRecord::Base has_many :developer_key_account_bindings, inverse_of: :account, dependent: :destroy has_many :authentication_providers, -> { order(:position) }, - extend: AccountAuthorizationConfig::FindWithType, - class_name: "AccountAuthorizationConfig" + inverse_of: :account, + extend: AuthenticationProvider::FindWithType has_many :account_reports has_many :grading_standards, -> { where("workflow_state<>'deleted'") }, as: :context, inverse_of: :context @@ -303,7 +303,7 @@ class Account < ActiveRecord::Base def enable_canvas_authentication return unless root_account? # for migrations creating a new db - return unless AccountAuthorizationConfig::Canvas.columns_hash.key?('workflow_state') + return unless AuthenticationProvider::Canvas.columns_hash.key?('workflow_state') return if authentication_providers.active.where(auth_type: 'canvas').exists? authentication_providers.create!(auth_type: 'canvas') end @@ -959,12 +959,12 @@ class Account < ActiveRecord::Base if login_handle_name_is_customized? self.login_handle_name elsif self.delegated_authentication? - AccountAuthorizationConfig.default_delegated_login_handle_name + AuthenticationProvider.default_delegated_login_handle_name end end def login_handle_name_with_inference - customized_login_handle_name || AccountAuthorizationConfig.default_login_handle_name + customized_login_handle_name || AuthenticationProvider.default_login_handle_name end def self_and_all_sub_accounts @@ -1106,7 +1106,7 @@ class Account < ActiveRecord::Base end def delegated_authentication? - authentication_providers.active.first.is_a?(AccountAuthorizationConfig::Delegated) + authentication_providers.active.first.is_a?(AuthenticationProvider::Delegated) end def forgot_password_external_url diff --git a/app/models/account_authorization_config.rb b/app/models/account_authorization_config.rb index fb7e74f7f93..687bfb8d7e7 100644 --- a/app/models/account_authorization_config.rb +++ b/app/models/account_authorization_config.rb @@ -16,331 +16,5 @@ # with this program. If not, see . # -require 'net-ldap' -require 'net_ldap_extensions' - -class AccountAuthorizationConfig < ActiveRecord::Base - include Workflow - validates :auth_filter, length: {maximum: maximum_text_length, allow_nil: true, allow_blank: true} - - workflow do - state :active - state :deleted - end - - self.inheritance_column = :auth_type - - def self.subclass_from_attributes?(attrs) - false - end - - # we have a lot of old data that didn't actually use STI, - # so we shim it - def self.find_sti_class(type_name) - return self if type_name.blank? # super no longer does this in Rails 4 - case type_name - when 'cas', 'ldap', 'saml' - const_get(type_name.upcase) - when 'clever', 'facebook', 'google', 'microsoft', 'twitter' - const_get(type_name.classify) - when 'canvas' - Canvas - when 'github' - GitHub - when 'linkedin' - LinkedIn - when 'openid_connect' - OpenIDConnect - else - super - end - end - - def self.sti_name - display_name.try(:underscore) - end - - def self.singleton? - false - end - - def self.enabled? - true - end - - def self.display_name - name.try(:demodulize) - end - - scope :active, ->{ where("workflow_state <> 'deleted'") } - belongs_to :account - has_many :pseudonyms, foreign_key: :authentication_provider_id - acts_as_list scope: { account: self, workflow_state: [nil, 'active'] } - - VALID_AUTH_TYPES = %w[canvas cas clever facebook github google ldap linkedin microsoft openid_connect saml twitter].freeze - validates_inclusion_of :auth_type, in: VALID_AUTH_TYPES, message: "invalid auth_type, must be one of #{VALID_AUTH_TYPES.join(',')}" - validates_presence_of :account_id - validate :validate_federated_attributes - - # create associate model find to accept auth types, and just return the first one of that - # type - module FindWithType - def find(*args) - if VALID_AUTH_TYPES.include?(args.first) - where(auth_type: args.first).first! - else - super - end - end - end - - def self.recognized_params - [].freeze - end - - def self.deprecated_params - [].freeze - end - - SENSITIVE_PARAMS = [].freeze - - def self.login_button? - Rails.root.join("public/images/sso_buttons/sso-#{sti_name}.svg").exist? - end - - def destroy - self.send(:remove_from_list_for_destroy) - self.workflow_state = 'deleted' - self.save! - enable_canvas_authentication - send_later_if_production(:soft_delete_pseudonyms) - true - end - alias_method :destroy_permanently!, :destroy - - def auth_password=(password) - return if password.blank? - self.auth_crypted_password, self.auth_password_salt = ::Canvas::Security.encrypt_password(password, 'instructure_auth') - end - - def auth_decrypted_password - return nil unless self.auth_password_salt && self.auth_crypted_password - ::Canvas::Security.decrypt_password(self.auth_crypted_password, self.auth_password_salt, 'instructure_auth') - end - - def auth_provider_filter - self - end - - def self.default_login_handle_name - t(:default_login_handle_name, "Email") - end - - def self.default_delegated_login_handle_name - t(:default_delegated_login_handle_name, "Login") - end - - def self.serialization_excludes; [:auth_crypted_password, :auth_password_salt]; end - - # allowable attributes for federated_attributes setting; nil means anything - # is allowed - def self.recognized_federated_attributes - [].freeze - end - - def settings - read_attribute(:settings) || {} - end - - def federated_attributes=(value) - value = {} unless value.is_a?(Hash) - settings_will_change! unless value == federated_attributes - settings['federated_attributes'] = value - end - - def federated_attributes - settings['federated_attributes'] ||= {} - end - - def federated_attributes_for_api - if jit_provisioning? - federated_attributes - else - result = {} - federated_attributes.each do |(canvas_attribute_name, provider_attribute_config)| - next if provider_attribute_config['provisioning_only'] - result[canvas_attribute_name] = provider_attribute_config['attribute'] - end - result - end - end - - CANVAS_ALLOWED_FEDERATED_ATTRIBUTES = %w{ - admin_roles - display_name - email - given_name - integration_id - locale - name - sis_user_id - sortable_name - surname - time_zone - }.freeze - - def provision_user(unique_id, provider_attributes = {}) - User.transaction(requires_new: true) do - pseudonym = account.pseudonyms.build - pseudonym.user = User.create!(name: unique_id) { |u| u.workflow_state = 'registered' } - pseudonym.authentication_provider = self - pseudonym.unique_id = unique_id - pseudonym.save! - apply_federated_attributes(pseudonym, provider_attributes, purpose: :provisioning) - pseudonym - end - rescue ActiveRecord::RecordNotUnique - uncached do - pseudonyms.active.by_unique_id(unique_id).take! - end - end - - def apply_federated_attributes(pseudonym, provider_attributes, purpose: :login) - user = pseudonym.user - - canvas_attributes = translate_provider_attributes(provider_attributes, - purpose: purpose) - given_name = canvas_attributes.delete('given_name') - surname = canvas_attributes.delete('surname') - if given_name || surname - user.name = "#{given_name} #{surname}" - user.sortable_name = if given_name.present? && surname.present? - "#{surname}, #{given_name}" - else - "#{given_name}#{surname}" - end - end - - canvas_attributes.each do |(attribute, value)| - case attribute - when 'admin_roles' - role_names = value.is_a?(String) ? value.split(',').map(&:strip) : value - account = pseudonym.account - existing_account_users = account.account_users.merge(user.account_users).preload(:role).to_a - roles = role_names.map do |role_name| - account.get_account_role_by_name(role_name) - end.compact - roles_to_add = roles - existing_account_users.map(&:role) - account_users_to_delete = existing_account_users.select { |au| au.active? && !roles.include?(au.role) } - account_users_to_activate = existing_account_users.select { |au| au.deleted? && roles.include?(au.role) } - roles_to_add.each do |role| - account.account_users.create!(user: user, role: role) - end - account_users_to_delete.each(&:destroy) - account_users_to_activate.each(&:reactivate) - when 'sis_user_id', 'integration_id' - pseudonym[attribute] = value - when 'display_name' - user.short_name = value - when 'email' - cc = user.communication_channels.email.by_path(value).first - cc ||= user.communication_channels.email.new(path: value) - cc.workflow_state = 'active' - cc.save! if cc.changed? - when 'locale' - # convert _ to -, be lenient about case, and perform fallbacks - value = value.tr('_', '-') - lowercase_locales = I18n.available_locales.map(&:to_s).map(&:downcase) - while value.include?('-') - break if lowercase_locales.include?(value.downcase) - value = value.sub(/(?:x-)?-[^-]*$/, '') - end - if (i = lowercase_locales.index(value.downcase)) - user.locale = I18n.available_locales[i].to_s - end - else - user.send("#{attribute}=", value) - end - end - if pseudonym.changed? - unless pseudonym.save - Rails.logger.warn("Unable to save federated pseudonym: #{pseudonym.errors}") - end - end - if user.changed? - unless user.save - Rails.logger.warn("Unable to save federated user: #{user.errors}") - end - end - end - - protected - - def statsd_prefix - "auth.account_#{Shard.global_id_for(account_id)}.config_#{self.global_id}" - end - - private - - def validate_federated_attributes - bad_keys = federated_attributes.keys - CANVAS_ALLOWED_FEDERATED_ATTRIBUTES - unless bad_keys.empty? - errors.add(:federated_attributes, "#{bad_keys.join(', ')} is not an attribute that can be federated") - return - end - - # normalize values to { attribute: , provisioning_only: true|false } - federated_attributes.keys.each do |key| - case federated_attributes[key] - when String - federated_attributes[key] = { 'attribute' => federated_attributes[key], 'provisioning_only' => false } - when Hash - bad_keys = federated_attributes[key].keys - ['attribute', 'provisioning_only'] - unless bad_keys.empty? - errors.add(:federated_attributes, "unrecognized key #{bad_keys.join(', ')} in #{key} attribute definition") - return - end - federated_attributes[key]['provisioning_only'] = - ::Canvas::Plugin.value_to_boolean(federated_attributes[key]['provisioning_only']) - else - errors.add(:federated_attributes, "invalid attribute definition for #{key}") - return - end - end - - return if self.class.recognized_federated_attributes.nil? - bad_values = federated_attributes.values.map { |v| v['attribute'] } - self.class.recognized_federated_attributes - unless bad_values.empty? - errors.add(:federated_attributes, "#{bad_values.join(', ')} is not a valid attribute") - end - end - - def translate_provider_attributes(provider_attributes, purpose:) - result = {} - federated_attributes.each do |(canvas_attribute_name, provider_attribute_config)| - next if purpose != :provisioning && provider_attribute_config['provisioning_only'] - provider_attribute_name = provider_attribute_config['attribute'] - - if provider_attributes.key?(provider_attribute_name) - result[canvas_attribute_name] = provider_attributes[provider_attribute_name] - end - end - result - end - - def soft_delete_pseudonyms - pseudonyms.find_each(&:destroy) - end - - def enable_canvas_authentication - return if account.non_canvas_auth_configured? - account.enable_canvas_authentication - end -end - -# so it doesn't get mixed up with ::CAS, ::LinkedIn and ::Twitter -require_dependency 'account_authorization_config/canvas' -require_dependency 'account_authorization_config/cas' -require_dependency 'account_authorization_config/google' -require_dependency 'account_authorization_config/linked_in' -require_dependency 'account_authorization_config/twitter' +# backcompat +AccountAuthorizationConfig = AuthenticationProvider diff --git a/app/models/authentication_provider.rb b/app/models/authentication_provider.rb new file mode 100644 index 00000000000..cc8a8213e59 --- /dev/null +++ b/app/models/authentication_provider.rb @@ -0,0 +1,366 @@ +# +# Copyright (C) 2011 - present Instructure, Inc. +# +# This file is part of Canvas. +# +# Canvas is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the Free +# Software Foundation, version 3 of the License. +# +# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see . +# + +require 'net-ldap' +require 'net_ldap_extensions' + +class AuthenticationProvider < ActiveRecord::Base + include Workflow + validates :auth_filter, length: {maximum: maximum_text_length, allow_nil: true, allow_blank: true} + + workflow do + state :active + state :deleted + end + + self.inheritance_column = :auth_type + # backcompat while authentication_providers might be a view + self.primary_key = 'id' + + def self.subclass_from_attributes?(_) + false + end + + # we have a lot of old data that didn't actually use STI, + # so we shim it + def self.find_sti_class(type_name) + return self if type_name.blank? # super no longer does this in Rails 4 + case type_name + when 'cas', 'ldap', 'saml' + const_get(type_name.upcase) + when 'clever', 'facebook', 'google', 'microsoft', 'twitter' + const_get(type_name.classify) + when 'canvas' + Canvas + when 'github' + GitHub + when 'linkedin' + LinkedIn + when 'openid_connect' + OpenIDConnect + else + super + end + end + + def self.sti_name + display_name.try(:underscore) + end + + def self.singleton? + false + end + + def self.enabled? + true + end + + def self.display_name + name.try(:demodulize) + end + + # Drop and recreate the authentication_providers view, if it exists. + # + # to be used from migrations that existed before the table rename. should + # only be used from inside a transaction. + def self.maybe_recreate_view + if (view_exists = connection.view_exists?("authentication_providers")) + connection.execute("DROP VIEW #{connection.quote_table_name('authentication_providers')}") + end + yield + if view_exists + connection.execute("CREATE VIEW #{connection.quote_table_name('authentication_providers')} AS SELECT * FROM #{connection.quote_table_name('account_authorization_configs')}") + end + end + + scope :active, ->{ where("workflow_state <> 'deleted'") } + belongs_to :account + has_many :pseudonyms, foreign_key: :authentication_provider_id, inverse_of: :authentication_provider + acts_as_list scope: { account: self, workflow_state: [nil, 'active'] } + + VALID_AUTH_TYPES = %w[canvas cas clever facebook github google ldap linkedin microsoft openid_connect saml twitter].freeze + validates :auth_type, + inclusion: { in: VALID_AUTH_TYPES, + message: "invalid auth_type, must be one of #{VALID_AUTH_TYPES.join(',')}" } + validates :account_id, presence: true + validate :validate_federated_attributes + + # create associate model find to accept auth types, and just return the first one of that + # type + module FindWithType + def find(*args) + if VALID_AUTH_TYPES.include?(args.first) + where(auth_type: args.first).first! + else + super + end + end + end + + def self.recognized_params + [].freeze + end + + def self.deprecated_params + [].freeze + end + + SENSITIVE_PARAMS = [].freeze + + def self.login_button? + Rails.root.join("public/images/sso_buttons/sso-#{sti_name}.svg").exist? + end + + def destroy + self.send(:remove_from_list_for_destroy) + self.workflow_state = 'deleted' + self.save! + enable_canvas_authentication + send_later_if_production(:soft_delete_pseudonyms) + true + end + alias destroy_permanently! destroy + + def auth_password=(password) + return if password.blank? + self.auth_crypted_password, self.auth_password_salt = ::Canvas::Security.encrypt_password(password, 'instructure_auth') + end + + def auth_decrypted_password + return nil unless self.auth_password_salt && self.auth_crypted_password + ::Canvas::Security.decrypt_password(self.auth_crypted_password, self.auth_password_salt, 'instructure_auth') + end + + def auth_provider_filter + self + end + + def self.default_login_handle_name + t(:default_login_handle_name, "Email") + end + + def self.default_delegated_login_handle_name + t(:default_delegated_login_handle_name, "Login") + end + + def self.serialization_excludes + [:auth_crypted_password, :auth_password_salt] + end + + # allowable attributes for federated_attributes setting; nil means anything + # is allowed + def self.recognized_federated_attributes + [].freeze + end + + def settings + read_attribute(:settings) || {} + end + + def federated_attributes=(value) + value = {} unless value.is_a?(Hash) + settings_will_change! unless value == federated_attributes + settings['federated_attributes'] = value + end + + def federated_attributes + settings['federated_attributes'] ||= {} + end + + def federated_attributes_for_api + if jit_provisioning? + federated_attributes + else + result = {} + federated_attributes.each do |(canvas_attribute_name, provider_attribute_config)| + next if provider_attribute_config['provisioning_only'] + result[canvas_attribute_name] = provider_attribute_config['attribute'] + end + result + end + end + + CANVAS_ALLOWED_FEDERATED_ATTRIBUTES = %w{ + admin_roles + display_name + email + given_name + integration_id + locale + name + sis_user_id + sortable_name + surname + time_zone + }.freeze + + def provision_user(unique_id, provider_attributes = {}) + User.transaction(requires_new: true) do + pseudonym = account.pseudonyms.build + pseudonym.user = User.create!(name: unique_id) { |u| u.workflow_state = 'registered' } + pseudonym.authentication_provider = self + pseudonym.unique_id = unique_id + pseudonym.save! + apply_federated_attributes(pseudonym, provider_attributes, purpose: :provisioning) + pseudonym + end + rescue ActiveRecord::RecordNotUnique + uncached do + pseudonyms.active.by_unique_id(unique_id).take! + end + end + + def apply_federated_attributes(pseudonym, provider_attributes, purpose: :login) + user = pseudonym.user + + canvas_attributes = translate_provider_attributes(provider_attributes, + purpose: purpose) + given_name = canvas_attributes.delete('given_name') + surname = canvas_attributes.delete('surname') + if given_name || surname + user.name = "#{given_name} #{surname}" + user.sortable_name = if given_name.present? && surname.present? + "#{surname}, #{given_name}" + else + "#{given_name}#{surname}" + end + end + + canvas_attributes.each do |(attribute, value)| + case attribute + when 'admin_roles' + role_names = value.is_a?(String) ? value.split(',').map(&:strip) : value + account = pseudonym.account + existing_account_users = account.account_users.merge(user.account_users).preload(:role).to_a + roles = role_names.map do |role_name| + account.get_account_role_by_name(role_name) + end.compact + roles_to_add = roles - existing_account_users.map(&:role) + account_users_to_delete = existing_account_users.select { |au| au.active? && !roles.include?(au.role) } + account_users_to_activate = existing_account_users.select { |au| au.deleted? && roles.include?(au.role) } + roles_to_add.each do |role| + account.account_users.create!(user: user, role: role) + end + account_users_to_delete.each(&:destroy) + account_users_to_activate.each(&:reactivate) + when 'sis_user_id', 'integration_id' + pseudonym[attribute] = value + when 'display_name' + user.short_name = value + when 'email' + cc = user.communication_channels.email.by_path(value).first + cc ||= user.communication_channels.email.new(path: value) + cc.workflow_state = 'active' + cc.save! if cc.changed? + when 'locale' + # convert _ to -, be lenient about case, and perform fallbacks + value = value.tr('_', '-') + lowercase_locales = I18n.available_locales.map(&:to_s).map(&:downcase) + while value.include?('-') + break if lowercase_locales.include?(value.downcase) + value = value.sub(/(?:x-)?-[^-]*$/, '') + end + if (i = lowercase_locales.index(value.downcase)) + user.locale = I18n.available_locales[i].to_s + end + else + user.send("#{attribute}=", value) + end + end + if pseudonym.changed? + unless pseudonym.save + Rails.logger.warn("Unable to save federated pseudonym: #{pseudonym.errors}") + end + end + if user.changed? + unless user.save + Rails.logger.warn("Unable to save federated user: #{user.errors}") + end + end + end + + protected + + def statsd_prefix + "auth.account_#{Shard.global_id_for(account_id)}.config_#{self.global_id}" + end + + private + + def validate_federated_attributes + bad_keys = federated_attributes.keys - CANVAS_ALLOWED_FEDERATED_ATTRIBUTES + unless bad_keys.empty? + errors.add(:federated_attributes, "#{bad_keys.join(', ')} is not an attribute that can be federated") + return + end + + # normalize values to { attribute: , provisioning_only: true|false } + federated_attributes.each_key do |key| + case federated_attributes[key] + when String + federated_attributes[key] = { 'attribute' => federated_attributes[key], 'provisioning_only' => false } + when Hash + bad_keys = federated_attributes[key].keys - ['attribute', 'provisioning_only'] + unless bad_keys.empty? + errors.add(:federated_attributes, "unrecognized key #{bad_keys.join(', ')} in #{key} attribute definition") + return + end + federated_attributes[key]['provisioning_only'] = + ::Canvas::Plugin.value_to_boolean(federated_attributes[key]['provisioning_only']) + else + errors.add(:federated_attributes, "invalid attribute definition for #{key}") + return + end + end + + return if self.class.recognized_federated_attributes.nil? + bad_values = federated_attributes.values.map { |v| v['attribute'] } - self.class.recognized_federated_attributes + unless bad_values.empty? + errors.add(:federated_attributes, "#{bad_values.join(', ')} is not a valid attribute") + end + end + + def translate_provider_attributes(provider_attributes, purpose:) + result = {} + federated_attributes.each do |(canvas_attribute_name, provider_attribute_config)| + next if purpose != :provisioning && provider_attribute_config['provisioning_only'] + provider_attribute_name = provider_attribute_config['attribute'] + + if provider_attributes.key?(provider_attribute_name) + result[canvas_attribute_name] = provider_attributes[provider_attribute_name] + end + end + result + end + + def soft_delete_pseudonyms + pseudonyms.find_each(&:destroy) + end + + def enable_canvas_authentication + return if account.non_canvas_auth_configured? + account.enable_canvas_authentication + end +end + +# so it doesn't get mixed up with ::CAS, ::LinkedIn and ::Twitter +require_dependency 'authentication_provider/canvas' +require_dependency 'authentication_provider/cas' +require_dependency 'authentication_provider/google' +require_dependency 'authentication_provider/linked_in' +require_dependency 'authentication_provider/twitter' diff --git a/app/models/account_authorization_config/canvas.rb b/app/models/authentication_provider/canvas.rb similarity index 95% rename from app/models/account_authorization_config/canvas.rb rename to app/models/authentication_provider/canvas.rb index bbb28040e34..0b70bff2b90 100644 --- a/app/models/account_authorization_config/canvas.rb +++ b/app/models/authentication_provider/canvas.rb @@ -16,7 +16,7 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::Canvas < AccountAuthorizationConfig +class AuthenticationProvider::Canvas < AuthenticationProvider def self.sti_name 'canvas' end diff --git a/app/models/account_authorization_config/cas.rb b/app/models/authentication_provider/cas.rb similarity index 94% rename from app/models/account_authorization_config/cas.rb rename to app/models/authentication_provider/cas.rb index 0a617b43ed8..3620b8af1aa 100644 --- a/app/models/account_authorization_config/cas.rb +++ b/app/models/authentication_provider/cas.rb @@ -18,7 +18,7 @@ require 'casclient' -class AccountAuthorizationConfig::CAS < AccountAuthorizationConfig::Delegated +class AuthenticationProvider::CAS < AuthenticationProvider::Delegated def self.sti_name 'cas'.freeze diff --git a/app/models/account_authorization_config/clever.rb b/app/models/authentication_provider/clever.rb similarity index 94% rename from app/models/account_authorization_config/clever.rb rename to app/models/authentication_provider/clever.rb index 7b5711eb86e..e5a1e27a366 100644 --- a/app/models/account_authorization_config/clever.rb +++ b/app/models/authentication_provider/clever.rb @@ -16,8 +16,8 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::Clever < AccountAuthorizationConfig::Oauth2 - include AccountAuthorizationConfig::PluginSettings +class AuthenticationProvider::Clever < AuthenticationProvider::Oauth2 + include AuthenticationProvider::PluginSettings self.plugin = :clever plugin_settings :client_id, client_secret: :client_secret_dec diff --git a/app/models/account_authorization_config/delegated.rb b/app/models/authentication_provider/delegated.rb similarity index 87% rename from app/models/account_authorization_config/delegated.rb rename to app/models/authentication_provider/delegated.rb index ef0dbf8abe4..5e3c6be0381 100644 --- a/app/models/account_authorization_config/delegated.rb +++ b/app/models/authentication_provider/delegated.rb @@ -16,7 +16,7 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::Delegated < AccountAuthorizationConfig +class AuthenticationProvider::Delegated < AuthenticationProvider after_create :disable_open_registration def disable_open_registration @@ -32,8 +32,8 @@ class AccountAuthorizationConfig::Delegated < AccountAuthorizationConfig # Canvas or LDAP primary provider; go to the login url cause it won't # auto-log them back in primary_auth = account.authentication_providers.active.first - if primary_auth.is_a?(AccountAuthorizationConfig::Canvas) || - primary_auth.is_a?(AccountAuthorizationConfig::LDAP) + if primary_auth.is_a?(AuthenticationProvider::Canvas) || + primary_auth.is_a?(AuthenticationProvider::LDAP) return controller.login_url end # otherwise, just go to a landing page diff --git a/app/models/account_authorization_config/facebook.rb b/app/models/authentication_provider/facebook.rb similarity index 94% rename from app/models/account_authorization_config/facebook.rb rename to app/models/authentication_provider/facebook.rb index 8fa35224a95..002b7d51b51 100644 --- a/app/models/account_authorization_config/facebook.rb +++ b/app/models/authentication_provider/facebook.rb @@ -16,8 +16,8 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::Facebook < AccountAuthorizationConfig::Oauth2 - include AccountAuthorizationConfig::PluginSettings +class AuthenticationProvider::Facebook < AuthenticationProvider::Oauth2 + include AuthenticationProvider::PluginSettings self.plugin = :facebook plugin_settings :app_id, app_secret: :app_secret_dec diff --git a/app/models/account_authorization_config/git_hub.rb b/app/models/authentication_provider/git_hub.rb similarity index 94% rename from app/models/account_authorization_config/git_hub.rb rename to app/models/authentication_provider/git_hub.rb index de16b6e874a..e78e1669851 100644 --- a/app/models/account_authorization_config/git_hub.rb +++ b/app/models/authentication_provider/git_hub.rb @@ -16,8 +16,8 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::GitHub < AccountAuthorizationConfig::Oauth2 - include AccountAuthorizationConfig::PluginSettings +class AuthenticationProvider::GitHub < AuthenticationProvider::Oauth2 + include AuthenticationProvider::PluginSettings self.plugin = :github plugin_settings :domain, :client_id, client_secret: :client_secret_dec diff --git a/app/models/account_authorization_config/google.rb b/app/models/authentication_provider/google.rb similarity index 94% rename from app/models/account_authorization_config/google.rb rename to app/models/authentication_provider/google.rb index fd8fedebeb9..30cfeb7b244 100644 --- a/app/models/account_authorization_config/google.rb +++ b/app/models/authentication_provider/google.rb @@ -16,8 +16,8 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::Google < AccountAuthorizationConfig::OpenIDConnect - include AccountAuthorizationConfig::PluginSettings +class AuthenticationProvider::Google < AuthenticationProvider::OpenIDConnect + include AuthenticationProvider::PluginSettings self.plugin = :google_drive plugin_settings :client_id, client_secret: :client_secret_dec diff --git a/app/models/account_authorization_config/ldap.rb b/app/models/authentication_provider/ldap.rb similarity index 97% rename from app/models/account_authorization_config/ldap.rb rename to app/models/authentication_provider/ldap.rb index d378f1ea374..a51b91b6204 100644 --- a/app/models/account_authorization_config/ldap.rb +++ b/app/models/authentication_provider/ldap.rb @@ -16,7 +16,7 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::LDAP < AccountAuthorizationConfig +class AuthenticationProvider::LDAP < AuthenticationProvider def self.sti_name 'ldap'.freeze end @@ -156,10 +156,10 @@ class AccountAuthorizationConfig::LDAP < AccountAuthorizationConfig rescue Timeout::Error self.errors.add(:ldap_bind_test, t("Timeout when searching")) return false - rescue + rescue => e self.errors.add( :ldap_search_test, - t(:test_search_failed, "Search failed with the following error: %{error}", :error => $!) + t(:test_search_failed, "Search failed with the following error: %{error}", :error => e) ) return false end @@ -174,10 +174,10 @@ class AccountAuthorizationConfig::LDAP < AccountAuthorizationConfig :ldap_login_test, t(:test_login_auth_failed, "Authentication failed") ) - rescue Net::LDAP::LdapError + rescue Net::LDAP::LdapError => e self.errors.add( :ldap_login_test, - t(:test_login_auth_exception, "Exception on login: %{error}", :error => $!) + t(:test_login_auth_exception, "Exception on login: %{error}", :error => e) ) end false diff --git a/app/models/account_authorization_config/linked_in.rb b/app/models/authentication_provider/linked_in.rb similarity index 94% rename from app/models/account_authorization_config/linked_in.rb rename to app/models/authentication_provider/linked_in.rb index a39747e60a6..bb890df6d4d 100644 --- a/app/models/account_authorization_config/linked_in.rb +++ b/app/models/authentication_provider/linked_in.rb @@ -16,8 +16,8 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::LinkedIn < AccountAuthorizationConfig::Oauth2 - include AccountAuthorizationConfig::PluginSettings +class AuthenticationProvider::LinkedIn < AuthenticationProvider::Oauth2 + include AuthenticationProvider::PluginSettings self.plugin = :linked_in plugin_settings :client_id, client_secret: :client_secret_dec diff --git a/app/models/account_authorization_config/microsoft.rb b/app/models/authentication_provider/microsoft.rb similarity index 94% rename from app/models/account_authorization_config/microsoft.rb rename to app/models/authentication_provider/microsoft.rb index 21718dd3421..2914b6742fb 100644 --- a/app/models/account_authorization_config/microsoft.rb +++ b/app/models/authentication_provider/microsoft.rb @@ -16,8 +16,8 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::Microsoft < AccountAuthorizationConfig::OpenIDConnect - include AccountAuthorizationConfig::PluginSettings +class AuthenticationProvider::Microsoft < AuthenticationProvider::OpenIDConnect + include AuthenticationProvider::PluginSettings self.plugin = :microsoft plugin_settings :application_id, application_secret: :application_secret_dec diff --git a/app/models/account_authorization_config/oauth.rb b/app/models/authentication_provider/oauth.rb similarity index 93% rename from app/models/account_authorization_config/oauth.rb rename to app/models/authentication_provider/oauth.rb index cb3214e08f2..2405493f2ca 100644 --- a/app/models/account_authorization_config/oauth.rb +++ b/app/models/authentication_provider/oauth.rb @@ -19,7 +19,7 @@ require 'oauth2' require 'canvas/core_ext/oauth2' -class AccountAuthorizationConfig::Oauth < AccountAuthorizationConfig::Delegated +class AuthenticationProvider::Oauth < AuthenticationProvider::Delegated SENSITIVE_PARAMS = [ :consumer_secret ].freeze diff --git a/app/models/account_authorization_config/oauth2.rb b/app/models/authentication_provider/oauth2.rb similarity index 93% rename from app/models/account_authorization_config/oauth2.rb rename to app/models/authentication_provider/oauth2.rb index 4499acc7551..5650a2a3fab 100644 --- a/app/models/account_authorization_config/oauth2.rb +++ b/app/models/authentication_provider/oauth2.rb @@ -19,7 +19,7 @@ require 'oauth2' require 'canvas/core_ext/oauth2' -class AccountAuthorizationConfig::Oauth2 < AccountAuthorizationConfig::Delegated +class AuthenticationProvider::Oauth2 < AuthenticationProvider::Delegated SENSITIVE_PARAMS = [ :client_secret ].freeze @@ -43,7 +43,7 @@ class AccountAuthorizationConfig::Oauth2 < AccountAuthorizationConfig::Delegated client.auth_code.get_token(code, { redirect_uri: redirect_uri }.merge(token_options)) end - def provider_attributes(token) + def provider_attributes(_token) {} end diff --git a/app/models/account_authorization_config/open_id_connect.rb b/app/models/authentication_provider/open_id_connect.rb similarity index 97% rename from app/models/account_authorization_config/open_id_connect.rb rename to app/models/authentication_provider/open_id_connect.rb index 5f2d18d6dc0..59fff498c7f 100644 --- a/app/models/account_authorization_config/open_id_connect.rb +++ b/app/models/authentication_provider/open_id_connect.rb @@ -16,7 +16,7 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::OpenIDConnect < AccountAuthorizationConfig::Oauth2 +class AuthenticationProvider::OpenIDConnect < AuthenticationProvider::Oauth2 def self.sti_name self == OpenIDConnect ? 'openid_connect'.freeze : super end diff --git a/app/models/account_authorization_config/plugin_settings.rb b/app/models/authentication_provider/plugin_settings.rb similarity index 97% rename from app/models/account_authorization_config/plugin_settings.rb rename to app/models/authentication_provider/plugin_settings.rb index 0459783fd0a..e2d89eace72 100644 --- a/app/models/account_authorization_config/plugin_settings.rb +++ b/app/models/authentication_provider/plugin_settings.rb @@ -16,7 +16,7 @@ # with this program. If not, see . # -module AccountAuthorizationConfig::PluginSettings +module AuthenticationProvider::PluginSettings module ClassMethods def singleton? true diff --git a/app/models/account_authorization_config/saml.rb b/app/models/authentication_provider/saml.rb similarity index 93% rename from app/models/account_authorization_config/saml.rb rename to app/models/authentication_provider/saml.rb index b3965014f1a..053ecf07579 100644 --- a/app/models/account_authorization_config/saml.rb +++ b/app/models/authentication_provider/saml.rb @@ -18,7 +18,7 @@ require 'saml2' -class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated +class AuthenticationProvider::SAML < AuthenticationProvider::Delegated def self.sti_name 'saml'.freeze end @@ -35,7 +35,8 @@ class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated end def self.recognized_params - [ :log_in_url, + [ + :log_in_url, :log_out_url, :requested_authn_context, :certificate_fingerprint, @@ -81,33 +82,33 @@ class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated end def download_metadata - return unless metadata_uri.present? + return if metadata_uri.blank? return unless metadata_uri_changed? || idp_entity_id_changed? Federation.descendants.each do |federation| # someone's trying to cheat; switch to our more efficient implementation self.metadata_uri = federation::URN if metadata_uri == federation.endpoint - if metadata_uri == federation::URN - unless idp_entity_id.present? - errors.add(:idp_entity_id, :present) - return - end + next unless metadata_uri == federation::URN - begin - entity = federation.metadata[idp_entity_id] - unless entity - errors.add(:idp_entity_id, t("Entity %{entity_id} not found in %{federation_name} Metadata", - entity_id: idp_entity_id, federation_name: federation.class_name)) - return - end - populate_from_metadata(entity) - rescue => e - ::Canvas::Errors.capture_exception(:saml_federation, e) - errors.add(:metadata_uri, e.message) - end + if idp_entity_id.blank? + errors.add(:idp_entity_id, :present) return end + + begin + entity = federation.metadata[idp_entity_id] + unless entity + errors.add(:idp_entity_id, t("Entity %{entity_id} not found in %{federation_name} Metadata", + entity_id: idp_entity_id, federation_name: federation.class_name)) + return + end + populate_from_metadata(entity) + rescue => e + ::Canvas::Errors.capture_exception(:saml_federation, e) + errors.add(:metadata_uri, e.message) + end + return end begin @@ -127,7 +128,7 @@ class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated end def self.saml_default_entity_id_for_account(account) - if !account.settings[:saml_entity_id] + unless account.settings[:saml_entity_id] account.settings[:saml_entity_id] = "http://#{HostUrl.context_host(account)}/saml2" account.save! end @@ -180,8 +181,8 @@ class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated self.sig_alg ||= 'RSA-SHA1' when false self.sig_alg = nil - # else nil - # don't change the user settings + # else nil + # don't change the user settings end end @@ -194,7 +195,7 @@ class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated raise "Must be a single Entity" unless entity.is_a?(SAML2::Entity) populate_from_metadata(entity) end - alias_method :metadata=, :populate_from_metadata_xml + alias metadata= populate_from_metadata_xml def populate_from_metadata_url(url) ::Canvas.timeout_protection("saml_metadata_fetch") do @@ -446,11 +447,10 @@ class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated session[:name_identifier_format], name_qualifier: session[:name_qualifier], sp_name_qualifier: session[:sp_name_qualifier]), - session[:session_index] - ) + session[:session_index]) # sign the response - private_key = AccountAuthorizationConfig::SAML.private_key + private_key = AuthenticationProvider::SAML.private_key private_key = nil if sig_alg.nil? result = SAML2::Bindings::HTTPRedirect.encode(logout_request, private_key: private_key, diff --git a/app/models/account_authorization_config/saml/federation.rb b/app/models/authentication_provider/saml/federation.rb similarity index 91% rename from app/models/account_authorization_config/saml/federation.rb rename to app/models/authentication_provider/saml/federation.rb index 645ee877ef7..8fe6d6ff212 100644 --- a/app/models/account_authorization_config/saml/federation.rb +++ b/app/models/authentication_provider/saml/federation.rb @@ -18,7 +18,7 @@ require 'saml2' -class AccountAuthorizationConfig::SAML::Federation < AccountAuthorizationConfig::SAML::MetadataRefresher +class AuthenticationProvider::SAML::Federation < AuthenticationProvider::SAML::MetadataRefresher class << self def metadata Shard.default.activate do @@ -32,7 +32,7 @@ class AccountAuthorizationConfig::SAML::Federation < AccountAuthorizationConfig: end def refresh_providers(shard_scope: Shard.in_current_region, providers: nil) - providers ||= AccountAuthorizationConfig::SAML.active. + providers ||= AuthenticationProvider::SAML.active. where(metadata_uri: self::URN).shard(shard_scope) # don't even bother checking the federation if no one is using it @@ -94,5 +94,5 @@ end # make sure to force these to eager load, otherwise we may try to iterate # all federations, but there won't be any -require_dependency 'account_authorization_config/saml/in_common' -require_dependency 'account_authorization_config/saml/uk_federation' +require_dependency 'authentication_provider/saml/in_common' +require_dependency 'authentication_provider/saml/uk_federation' diff --git a/app/models/account_authorization_config/saml/in_common.rb b/app/models/authentication_provider/saml/in_common.rb similarity index 85% rename from app/models/account_authorization_config/saml/in_common.rb rename to app/models/authentication_provider/saml/in_common.rb index f600b10318d..f7e7e57c53c 100644 --- a/app/models/account_authorization_config/saml/in_common.rb +++ b/app/models/authentication_provider/saml/in_common.rb @@ -18,7 +18,7 @@ require 'saml2' -class AccountAuthorizationConfig::SAML::InCommon < AccountAuthorizationConfig::SAML::Federation +class AuthenticationProvider::SAML::InCommon < AuthenticationProvider::SAML::Federation URN = 'urn:mace:incommon'.freeze class << self @@ -29,7 +29,7 @@ class AccountAuthorizationConfig::SAML::InCommon < AccountAuthorizationConfig::S protected def cert - Rails.root.join("config/saml/inc-md-cert.pem").read + Rails.root.join("config", "saml", "inc-md-cert.pem").read end end end diff --git a/app/models/account_authorization_config/saml/metadata_refresher.rb b/app/models/authentication_provider/saml/metadata_refresher.rb similarity index 85% rename from app/models/account_authorization_config/saml/metadata_refresher.rb rename to app/models/authentication_provider/saml/metadata_refresher.rb index fd8e3867a5f..a4d41014fe1 100644 --- a/app/models/account_authorization_config/saml/metadata_refresher.rb +++ b/app/models/authentication_provider/saml/metadata_refresher.rb @@ -18,13 +18,13 @@ require 'saml2' -class AccountAuthorizationConfig::SAML::MetadataRefresher +class AuthenticationProvider::SAML::MetadataRefresher class << self def refresh_providers(shard_scope: Shard.current, providers: nil) - federations = AccountAuthorizationConfig::SAML::Federation.descendants.map { |federation| federation::URN } - providers ||= AccountAuthorizationConfig::SAML.active. - where.not(metadata_uri: [nil, ""] + federations). - shard(shard_scope) + federations = AuthenticationProvider::SAML::Federation.descendants.map { |federation| federation::URN } + providers ||= AuthenticationProvider::SAML.active. + where.not(metadata_uri: [nil, ""] + federations). + shard(shard_scope) providers.each do |provider| begin diff --git a/app/models/account_authorization_config/saml/uk_federation.rb b/app/models/authentication_provider/saml/uk_federation.rb similarity index 85% rename from app/models/account_authorization_config/saml/uk_federation.rb rename to app/models/authentication_provider/saml/uk_federation.rb index 3ae4b8f948f..0a7734e1878 100644 --- a/app/models/account_authorization_config/saml/uk_federation.rb +++ b/app/models/authentication_provider/saml/uk_federation.rb @@ -18,7 +18,7 @@ require 'saml2' -class AccountAuthorizationConfig::SAML::UKFederation < AccountAuthorizationConfig::SAML::Federation +class AuthenticationProvider::SAML::UKFederation < AuthenticationProvider::SAML::Federation URN = 'http://ukfederation.org.uk'.freeze class << self @@ -29,7 +29,7 @@ class AccountAuthorizationConfig::SAML::UKFederation < AccountAuthorizationConfi protected def cert - Rails.root.join("config/saml/ukfederation.pem").read + Rails.root.join("config", "saml", "ukfederation.pem").read end end end diff --git a/app/models/account_authorization_config/twitter.rb b/app/models/authentication_provider/twitter.rb similarity index 93% rename from app/models/account_authorization_config/twitter.rb rename to app/models/authentication_provider/twitter.rb index ec56f53af51..5af381ef82d 100644 --- a/app/models/account_authorization_config/twitter.rb +++ b/app/models/authentication_provider/twitter.rb @@ -16,8 +16,8 @@ # with this program. If not, see . # -class AccountAuthorizationConfig::Twitter < AccountAuthorizationConfig::Oauth - include AccountAuthorizationConfig::PluginSettings +class AuthenticationProvider::Twitter < AuthenticationProvider::Oauth + include AuthenticationProvider::PluginSettings self.plugin = :twitter plugin_settings :consumer_key, consumer_secret: :consumer_secret_dec diff --git a/app/models/pseudonym.rb b/app/models/pseudonym.rb index 5fc6930a487..6b3330f3a5f 100644 --- a/app/models/pseudonym.rb +++ b/app/models/pseudonym.rb @@ -26,10 +26,10 @@ class Pseudonym < ActiveRecord::Base has_many :sis_enrollments, class_name: 'Enrollment', inverse_of: :sis_pseudonym belongs_to :communication_channel belongs_to :sis_communication_channel, :class_name => 'CommunicationChannel' - belongs_to :authentication_provider, class_name: 'AccountAuthorizationConfig' + belongs_to :authentication_provider MAX_UNIQUE_ID_LENGTH = 100 - CAS_TICKET_EXPIRED = 'expired' + CAS_TICKET_EXPIRED = 'expired'.freeze CAS_TICKET_TTL = 1.day validates_length_of :unique_id, :maximum => MAX_UNIQUE_ID_LENGTH @@ -136,8 +136,8 @@ class Pseudonym < ActiveRecord::Base def self.custom_find_by_unique_id(unique_id) return unless unique_id active.by_unique_id(unique_id).where("authentication_provider_id IS NULL OR EXISTS (?)", - AccountAuthorizationConfig.active.where(auth_type: ['canvas', 'ldap']). - where("authentication_provider_id=account_authorization_configs.id")).first + AuthenticationProvider.active.where(auth_type: ['canvas', 'ldap']). + where("authentication_provider_id=authentication_providers.id")).first end def self.for_auth_configuration(unique_id, aac) @@ -359,7 +359,7 @@ class Pseudonym < ActiveRecord::Base def managed_password? if authentication_provider # explicit provider we can be sure if it's managed or not - !authentication_provider.is_a?(AccountAuthorizationConfig::Canvas) + !authentication_provider.is_a?(AuthenticationProvider::Canvas) else # otherwise we have to guess !!(self.sis_user_id && account.non_canvas_auth_configured?) @@ -367,7 +367,7 @@ class Pseudonym < ActiveRecord::Base end def passwordable? - authentication_provider.is_a?(AccountAuthorizationConfig::Canvas) || + authentication_provider.is_a?(AuthenticationProvider::Canvas) || (!authentication_provider && account.canvas_authentication?) end @@ -422,14 +422,14 @@ class Pseudonym < ActiveRecord::Base def ldap_bind_result(password_plaintext) aps = case authentication_provider - when AccountAuthorizationConfig::LDAP + when AuthenticationProvider::LDAP [authentication_provider] when nil account.authentication_providers.active.where(auth_type: 'ldap') - #when AccountAuthorizationConfig::Canvas + # when AuthenticationProvider::Canvas else [] - end + end aps.each do |config| res = config.ldap_bind_result(self.unique_id, password_plaintext) return res if res diff --git a/app/presenters/account_authorization_configs_presenter.rb b/app/presenters/authentication_providers_presenter.rb similarity index 82% rename from app/presenters/account_authorization_configs_presenter.rb rename to app/presenters/authentication_providers_presenter.rb index 73e1f8eae43..eda14244abf 100644 --- a/app/presenters/account_authorization_configs_presenter.rb +++ b/app/presenters/authentication_providers_presenter.rb @@ -15,7 +15,7 @@ # You should have received a copy of the GNU Affero General Public License along # with this program. If not, see . -class AccountAuthorizationConfigsPresenter +class AuthenticationProvidersPresenter include ActionView::Helpers::FormTagHelper include ActionView::Helpers::FormOptionsHelper @@ -30,8 +30,8 @@ class AccountAuthorizationConfigsPresenter end def new_auth_types - AccountAuthorizationConfig::VALID_AUTH_TYPES.map do |auth_type| - klass = AccountAuthorizationConfig.find_sti_class(auth_type) + AuthenticationProvider::VALID_AUTH_TYPES.map do |auth_type| + klass = AuthenticationProvider.find_sti_class(auth_type) next unless klass.enabled? next if klass.singleton? && configs.any? { |aac| aac.is_a?(klass) } klass @@ -39,12 +39,12 @@ class AccountAuthorizationConfigsPresenter end def needs_unknown_user_url? - configs.any? { |c| c.is_a?(AccountAuthorizationConfig::Delegated) } + configs.any? { |c| c.is_a?(AuthenticationProvider::Delegated) } end def login_url_options(aac) options = { controller: "login/#{aac.auth_type}", action: :new } - if !aac.is_a?(AccountAuthorizationConfig::LDAP) && + if !aac.is_a?(AuthenticationProvider::LDAP) && configs.many? { |other| other.auth_type == aac.auth_type } options[:id] = aac end @@ -64,18 +64,17 @@ class AccountAuthorizationConfigsPresenter end def ldap_configs - configs.select{|c| c.is_a?(AccountAuthorizationConfig::LDAP) } + configs.select{|c| c.is_a?(AuthenticationProvider::LDAP) } end def saml_configs - configs.select{|c| c.is_a?(AccountAuthorizationConfig::SAML) } + configs.select{|c| c.is_a?(AuthenticationProvider::SAML) } end def cas_configs - configs.select{|c| c.is_a?(AccountAuthorizationConfig::CAS) } + configs.select{|c| c.is_a?(AuthenticationProvider::CAS) } end - def sso_options new_auth_types.map do |auth_type| { @@ -118,11 +117,11 @@ class AccountAuthorizationConfigsPresenter end def saml_enabled? - AccountAuthorizationConfig::SAML.enabled? + AuthenticationProvider::SAML.enabled? end def login_placeholder - AccountAuthorizationConfig.default_delegated_login_handle_name + AuthenticationProvider.default_delegated_login_handle_name end def login_name @@ -130,7 +129,7 @@ class AccountAuthorizationConfigsPresenter end def new_config(auth_type) - account.authentication_providers.new(auth_type) + AuthenticationProvider.new(auth_type: auth_type, account: account) end def parent_reg_selected @@ -138,7 +137,7 @@ class AccountAuthorizationConfigsPresenter end def available_federated_attributes(aac) - AccountAuthorizationConfig::CANVAS_ALLOWED_FEDERATED_ATTRIBUTES - aac.federated_attributes.keys + AuthenticationProvider::CANVAS_ALLOWED_FEDERATED_ATTRIBUTES - aac.federated_attributes.keys end def federated_provider_attribute(aac, canvas_attribute = nil, selected = nil) diff --git a/app/views/accounts/settings.html.erb b/app/views/accounts/settings.html.erb index 7f768c3b02c..b9690b9d158 100644 --- a/app/views/accounts/settings.html.erb +++ b/app/views/accounts/settings.html.erb @@ -144,7 +144,7 @@ <% unless @account.non_canvas_auth_configured? - # if the account has a account_authorization_config, + # if the account has a authentication_provider, # we'll control this setting from that page %> diff --git a/app/views/account_authorization_configs/_aac_settings.html.erb b/app/views/authentication_providers/_aac_settings.html.erb similarity index 100% rename from app/views/account_authorization_configs/_aac_settings.html.erb rename to app/views/authentication_providers/_aac_settings.html.erb diff --git a/app/views/account_authorization_configs/_canvas_fields.html.erb b/app/views/authentication_providers/_canvas_fields.html.erb similarity index 100% rename from app/views/account_authorization_configs/_canvas_fields.html.erb rename to app/views/authentication_providers/_canvas_fields.html.erb diff --git a/app/views/account_authorization_configs/_cas_fields.html.erb b/app/views/authentication_providers/_cas_fields.html.erb similarity index 100% rename from app/views/account_authorization_configs/_cas_fields.html.erb rename to app/views/authentication_providers/_cas_fields.html.erb diff --git a/app/views/account_authorization_configs/_clever_fields.html.erb b/app/views/authentication_providers/_clever_fields.html.erb similarity index 96% rename from app/views/account_authorization_configs/_clever_fields.html.erb rename to app/views/authentication_providers/_clever_fields.html.erb index cf8005b0bc1..c8ba25fc7c0 100644 --- a/app/views/account_authorization_configs/_clever_fields.html.erb +++ b/app/views/authentication_providers/_clever_fields.html.erb @@ -16,7 +16,7 @@ # with this program. If not, see . %> -<% unless AccountAuthorizationConfig::Clever.globally_configured? %> +<% unless AuthenticationProvider::Clever.globally_configured? %>

<%= mt(<<-TEXT, clever_url: "http://apps.clever.com/signup", callback_url: clever_callback_url) You will need to [register an application on Clever](%{clever_url}). You should configure %{callback_url} as the Redirect URL. diff --git a/app/views/account_authorization_configs/_facebook_fields.html.erb b/app/views/authentication_providers/_facebook_fields.html.erb similarity index 96% rename from app/views/account_authorization_configs/_facebook_fields.html.erb rename to app/views/authentication_providers/_facebook_fields.html.erb index b4e361cca55..4d5423dd7c0 100644 --- a/app/views/account_authorization_configs/_facebook_fields.html.erb +++ b/app/views/authentication_providers/_facebook_fields.html.erb @@ -16,7 +16,7 @@ # with this program. If not, see . %> -<% unless AccountAuthorizationConfig::Facebook.globally_configured? %> +<% unless AuthenticationProvider::Facebook.globally_configured? %>

<%= mt(<<-TEXT, facebook_url: "https://developers.facebook.com/", callback_url: oauth2_login_callback_url) You will need to create a [new app on Facebook](%{facebook_url}), and enable Client OAuth Login in Advanced Settings. You should configure %{callback_url} as the Valid OAuth redirect URI. diff --git a/app/views/account_authorization_configs/_federated_attributes.html.erb b/app/views/authentication_providers/_federated_attributes.html.erb similarity index 100% rename from app/views/account_authorization_configs/_federated_attributes.html.erb rename to app/views/authentication_providers/_federated_attributes.html.erb diff --git a/app/views/account_authorization_configs/_github_fields.html.erb b/app/views/authentication_providers/_github_fields.html.erb similarity index 95% rename from app/views/account_authorization_configs/_github_fields.html.erb rename to app/views/authentication_providers/_github_fields.html.erb index d84ffc1ab98..44210d965ff 100644 --- a/app/views/account_authorization_configs/_github_fields.html.erb +++ b/app/views/authentication_providers/_github_fields.html.erb @@ -16,7 +16,7 @@ # with this program. If not, see . %> -<% unless AccountAuthorizationConfig::GitHub.globally_configured? %> +<% unless AuthenticationProvider::GitHub.globally_configured? %>

<%= mt(<<-TEXT, github_url: "https://github.com/settings/developers", callback_url: oauth2_login_callback_url) You will need to [register an application on GitHub](%{github_url}). You should configure %{callback_url} as the Authorization callback URL. diff --git a/app/views/account_authorization_configs/_google_fields.html.erb b/app/views/authentication_providers/_google_fields.html.erb similarity index 96% rename from app/views/account_authorization_configs/_google_fields.html.erb rename to app/views/authentication_providers/_google_fields.html.erb index b27692629f8..a5a23a1e587 100644 --- a/app/views/account_authorization_configs/_google_fields.html.erb +++ b/app/views/authentication_providers/_google_fields.html.erb @@ -16,7 +16,7 @@ # with this program. If not, see . %> -<% unless AccountAuthorizationConfig::Google.globally_configured? %> +<% unless AuthenticationProvider::Google.globally_configured? %>

<%= mt(<<-TEXT, google_url: "https://console.developers.google.com/project", callback_url: oauth2_login_callback_url) You will need to create a web application in the [Google Developer Console](%{google_url}). You should add %{callback_url} as a redirect URI. diff --git a/app/views/account_authorization_configs/_jit_provisioning_field.html.erb b/app/views/authentication_providers/_jit_provisioning_field.html.erb similarity index 100% rename from app/views/account_authorization_configs/_jit_provisioning_field.html.erb rename to app/views/authentication_providers/_jit_provisioning_field.html.erb diff --git a/app/views/account_authorization_configs/_ldap_fields.html.erb b/app/views/authentication_providers/_ldap_fields.html.erb similarity index 100% rename from app/views/account_authorization_configs/_ldap_fields.html.erb rename to app/views/authentication_providers/_ldap_fields.html.erb diff --git a/app/views/account_authorization_configs/_ldap_settings_test.html.erb b/app/views/authentication_providers/_ldap_settings_test.html.erb similarity index 100% rename from app/views/account_authorization_configs/_ldap_settings_test.html.erb rename to app/views/authentication_providers/_ldap_settings_test.html.erb diff --git a/app/views/account_authorization_configs/_linkedin_fields.html.erb b/app/views/authentication_providers/_linkedin_fields.html.erb similarity index 95% rename from app/views/account_authorization_configs/_linkedin_fields.html.erb rename to app/views/authentication_providers/_linkedin_fields.html.erb index 2b36e78a39b..f709adbc964 100644 --- a/app/views/account_authorization_configs/_linkedin_fields.html.erb +++ b/app/views/authentication_providers/_linkedin_fields.html.erb @@ -16,7 +16,7 @@ # with this program. If not, see . %> -<% unless AccountAuthorizationConfig::LinkedIn.globally_configured? %> +<% unless AuthenticationProvider::LinkedIn.globally_configured? %>

<%= mt(:description, <<-TEXT, linkedin_url: 'https://www.linkedin.com/secure/developer', callback_url: oauth2_login_callback_url) You will need to [register an application on LinkedIn](%{linkedin_url}). You should add %{callback_url} as an OAuth 2.0 authorized redirect URL, and set the Application Status to Live diff --git a/app/views/account_authorization_configs/_login_attribute_dropdown.html.erb b/app/views/authentication_providers/_login_attribute_dropdown.html.erb similarity index 100% rename from app/views/account_authorization_configs/_login_attribute_dropdown.html.erb rename to app/views/authentication_providers/_login_attribute_dropdown.html.erb diff --git a/app/views/account_authorization_configs/_microsoft_fields.html.erb b/app/views/authentication_providers/_microsoft_fields.html.erb similarity index 97% rename from app/views/account_authorization_configs/_microsoft_fields.html.erb rename to app/views/authentication_providers/_microsoft_fields.html.erb index a2c10ba2431..b208c8d5081 100644 --- a/app/views/account_authorization_configs/_microsoft_fields.html.erb +++ b/app/views/authentication_providers/_microsoft_fields.html.erb @@ -16,7 +16,7 @@ # with this program. If not, see . %> -<% unless AccountAuthorizationConfig::Microsoft.globally_configured? %> +<% unless AuthenticationProvider::Microsoft.globally_configured? %>

<%= mt(<<-TEXT, ms_app_url: "https://apps.dev.microsoft.com/", callback_url: oauth2_login_callback_url) You will need to register a [new app with Microsoft](%{ms_app_url}). You should configure %{callback_url} as the Redirect URI. diff --git a/app/views/account_authorization_configs/_oauth2_fields.html.erb b/app/views/authentication_providers/_oauth2_fields.html.erb similarity index 100% rename from app/views/account_authorization_configs/_oauth2_fields.html.erb rename to app/views/authentication_providers/_oauth2_fields.html.erb diff --git a/app/views/account_authorization_configs/_openid_connect_fields.html.erb b/app/views/authentication_providers/_openid_connect_fields.html.erb similarity index 100% rename from app/views/account_authorization_configs/_openid_connect_fields.html.erb rename to app/views/authentication_providers/_openid_connect_fields.html.erb diff --git a/app/views/account_authorization_configs/_saml_fields.html.erb b/app/views/authentication_providers/_saml_fields.html.erb similarity index 100% rename from app/views/account_authorization_configs/_saml_fields.html.erb rename to app/views/authentication_providers/_saml_fields.html.erb diff --git a/app/views/account_authorization_configs/_saml_settings_test.html.erb b/app/views/authentication_providers/_saml_settings_test.html.erb similarity index 100% rename from app/views/account_authorization_configs/_saml_settings_test.html.erb rename to app/views/authentication_providers/_saml_settings_test.html.erb diff --git a/app/views/account_authorization_configs/_saml_testing.html.erb b/app/views/authentication_providers/_saml_testing.html.erb similarity index 100% rename from app/views/account_authorization_configs/_saml_testing.html.erb rename to app/views/authentication_providers/_saml_testing.html.erb diff --git a/app/views/account_authorization_configs/_sso_settings_form.html.erb b/app/views/authentication_providers/_sso_settings_form.html.erb similarity index 100% rename from app/views/account_authorization_configs/_sso_settings_form.html.erb rename to app/views/authentication_providers/_sso_settings_form.html.erb diff --git a/app/views/account_authorization_configs/_twitter_fields.html.erb b/app/views/authentication_providers/_twitter_fields.html.erb similarity index 96% rename from app/views/account_authorization_configs/_twitter_fields.html.erb rename to app/views/authentication_providers/_twitter_fields.html.erb index 7c358db179b..0140e4fb601 100644 --- a/app/views/account_authorization_configs/_twitter_fields.html.erb +++ b/app/views/authentication_providers/_twitter_fields.html.erb @@ -16,7 +16,7 @@ # with this program. If not, see . %> -<% unless AccountAuthorizationConfig::Twitter.globally_configured? %> +<% unless AuthenticationProvider::Twitter.globally_configured? %>

<%= mt(<<-TEXT, twitter_url: "https://apps.twitter.com/", callback_url: oauth_login_callback_url) You will need to [register an application on Twitter](%{twitter_url}). You should configure %{callback_url} as the Callback URL. diff --git a/app/views/account_authorization_configs/index.html.erb b/app/views/authentication_providers/index.html.erb similarity index 97% rename from app/views/account_authorization_configs/index.html.erb rename to app/views/authentication_providers/index.html.erb index 0112231d12a..4381a847d95 100644 --- a/app/views/account_authorization_configs/index.html.erb +++ b/app/views/authentication_providers/index.html.erb @@ -82,7 +82,6 @@

<%= t("Current Provider") %>

- <% if @presenter.configs.empty? %>
<%= t(:no_auth_type_description, "This account does not currently integrate "\ @@ -100,7 +99,7 @@ locals: { account: @account, presenter: @presenter, - aac: @presenter.new_config(auth_type: auth_type.sti_name) + aac: @presenter.new_config(auth_type.sti_name) } %> <% end %> @@ -114,4 +113,4 @@ locals: { account: @account, presenter: @presenter } %> <% end %> -<% js_bundle :account_authorization_configs %> +<% js_bundle :authentication_providers %> diff --git a/config/initializers/active_record.rb b/config/initializers/active_record.rb index 24f1e96fcc4..2c747f000c3 100644 --- a/config/initializers/active_record.rb +++ b/config/initializers/active_record.rb @@ -1603,3 +1603,17 @@ if CANVAS_RAILS5_1 end end end + +# fake Rails into grabbing correct column information for a table rename in-progress +module TableRename + RENAMES = { 'authentication_providers' => 'account_authorization_configs' }.freeze + + def columns(table_name) + if (old_name = RENAMES[table_name]) + table_name = old_name if connection.table_exists?(old_name) + end + super + end +end + +ActiveRecord::ConnectionAdapters::SchemaCache.prepend(TableRename) diff --git a/config/initializers/periodic_jobs.rb b/config/initializers/periodic_jobs.rb index 786e625271b..d0779c0e739 100644 --- a/config/initializers/periodic_jobs.rb +++ b/config/initializers/periodic_jobs.rb @@ -173,17 +173,17 @@ Rails.configuration.after_initialize do with_each_shard_by_database(Version::Partitioner, :process) end - if AccountAuthorizationConfig::SAML.enabled? - Delayed::Periodic.cron 'AccountAuthorizationConfig::SAML::MetadataRefresher.refresh_providers', '15 0 * * *' do - with_each_shard_by_database(AccountAuthorizationConfig::SAML::MetadataRefresher, + if AuthenticationProvider::SAML.enabled? + Delayed::Periodic.cron 'AuthenticationProvider::SAML::MetadataRefresher.refresh_providers', '15 0 * * *' do + with_each_shard_by_database(AuthenticationProvider::SAML::MetadataRefresher, :refresh_providers) end - AccountAuthorizationConfig::SAML::Federation.descendants.each do |federation| - Delayed::Periodic.cron "AccountAuthorizationConfig::SAML::#{federation.class_name}.refresh_providers", '45 0 * * *' do + AuthenticationProvider::SAML::Federation.descendants.each do |federation| + Delayed::Periodic.cron "AuthenticationProvider::SAML::#{federation.class_name}.refresh_providers", '45 0 * * *' do DatabaseServer.send_in_each_region(federation, :refresh_providers, - singleton: "AccountAuthorizationConfig::SAML::#{federation.class_name}.refresh_providers") + singleton: "AuthenticationProvider::SAML::#{federation.class_name}.refresh_providers") end end end diff --git a/config/routes.rb b/config/routes.rb index 38a277500ee..399fffc03fc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -599,17 +599,17 @@ CanvasRails::Application.routes.draw do resources :account_notifications, only: [:create, :update, :destroy] concerns :announcements resources :submissions - delete 'authentication_providers' => 'account_authorization_configs#destroy_all', as: :remove_all_authentication_providers - put 'sso_settings' => 'account_authorization_configs#update_sso_settings', + delete 'authentication_providers' => 'authentication_providers#destroy_all', as: :remove_all_authentication_providers + put 'sso_settings' => 'authentication_providers#update_sso_settings', as: :update_sso_settings - resources :authentication_providers, controller: :account_authorization_configs, only: [:index, :create, :update, :destroy] - get 'test_ldap_connections' => 'account_authorization_configs#test_ldap_connection' - get 'test_ldap_binds' => 'account_authorization_configs#test_ldap_bind' - get 'test_ldap_searches' => 'account_authorization_configs#test_ldap_search' - match 'test_ldap_logins' => 'account_authorization_configs#test_ldap_login', via: [:get, :post] - get 'saml_testing' => 'account_authorization_configs#saml_testing' - get 'saml_testing_stop' => 'account_authorization_configs#saml_testing_stop' + resources :authentication_providers, only: [:index, :create, :update, :destroy] + get 'test_ldap_connections' => 'authentication_providers#test_ldap_connection' + get 'test_ldap_binds' => 'authentication_providers#test_ldap_bind' + get 'test_ldap_searches' => 'authentication_providers#test_ldap_search' + match 'test_ldap_logins' => 'authentication_providers#test_ldap_login', via: [:get, :post] + get 'saml_testing' => 'authentication_providers#saml_testing' + get 'saml_testing_stop' => 'authentication_providers#saml_testing_stop' get 'external_tools/sessionless_launch' => 'external_tools#sessionless_launch' resources :external_tools do @@ -1364,7 +1364,7 @@ CanvasRails::Application.routes.draw do get 'accounts/:account_id/admins', action: :index, as: 'account_admins' end - scope(controller: :account_authorization_configs) do + scope(controller: :authentication_providers) do get 'accounts/:account_id/sso_settings', action: :show_sso_settings, as: 'account_show_sso_settings_url' put 'accounts/:account_id/sso_settings', action: :update_sso_settings, as: 'account_update_sso_settings_url' diff --git a/db/migrate/20111121175219_disable_open_registration_for_delegated_auth.rb b/db/migrate/20111121175219_disable_open_registration_for_delegated_auth.rb index 2dd1c3a23e2..d4ce01b7dd4 100644 --- a/db/migrate/20111121175219_disable_open_registration_for_delegated_auth.rb +++ b/db/migrate/20111121175219_disable_open_registration_for_delegated_auth.rb @@ -19,7 +19,7 @@ class DisableOpenRegistrationForDelegatedAuth < ActiveRecord::Migration[4.2] tag :predeploy def self.up - scope = Account.root_accounts.joins(:authentication_providers).readonly(false) + scope = Account.root_accounts.joins("INNER JOIN #{connection.quote_table_name('account_authorization_configs')} ON account_id=accounts.id").readonly(false) scope.where('account_authorization_configs.auth_type' => ['cas', 'saml']).each do |account| account.settings = { :open_registration => false } account.save! diff --git a/db/migrate/20120127035651_add_saml_requested_authn_context.rb b/db/migrate/20120127035651_add_saml_requested_authn_context.rb index f34d5a2c0cd..c4e1eed5d49 100644 --- a/db/migrate/20120127035651_add_saml_requested_authn_context.rb +++ b/db/migrate/20120127035651_add_saml_requested_authn_context.rb @@ -18,15 +18,19 @@ class AddSamlRequestedAuthnContext < ActiveRecord::Migration[4.2] tag :predeploy + class AuthenticationProvider < ActiveRecord::Base + self.table_name = 'account_authorization_configs' + end + def self.up add_column :account_authorization_configs, :requested_authn_context, :string - AccountAuthorizationConfig.where(auth_type: "saml").each do |aac| + AuthenticationProvider.where(auth_type: "saml").each do |aac| # This was the hard-coded value before aac.requested_authn_context = Onelogin::Saml::AuthnContexts::PASSWORD_PROTECTED_TRANSPORT aac.save! end - AccountAuthorizationConfig.reset_column_information + AuthenticationProvider.reset_column_information end def self.down diff --git a/db/migrate/20120921155127_add_saml_properties.rb b/db/migrate/20120921155127_add_saml_properties.rb index 1e78fc07cdc..2b626ace63b 100644 --- a/db/migrate/20120921155127_add_saml_properties.rb +++ b/db/migrate/20120921155127_add_saml_properties.rb @@ -21,21 +21,14 @@ class AddSamlProperties < ActiveRecord::Migration[4.2] def self.up add_column :account_authorization_configs, :idp_entity_id, :string add_column :account_authorization_configs, :position, :integer - if connection.adapter_name =~ /postgres/i - update <<-SQL - UPDATE #{AccountAuthorizationConfig.quoted_table_name} aac - SET position = - CASE WHEN (SELECT count(*) FROM #{AccountAuthorizationConfig.quoted_table_name} WHERE account_id = aac.account_id) > 1 - THEN aac.id - ELSE 1 - END; - SQL - else - update <<-SQL - UPDATE #{AccountAuthorizationConfig.quoted_table_name} - SET position = account_authorization_configs.id; - SQL - end + update <<-SQL + UPDATE #{connection.quote_table_name('account_authorization_configs')} aac + SET position = + CASE WHEN (SELECT count(*) FROM #{connection.quote_table_name('account_authorization_configs')} WHERE account_id = aac.account_id) > 1 + THEN aac.id + ELSE 1 + END; + SQL end def self.down diff --git a/db/migrate/20150507024319_drop_ldap_auth_settings_from_aacs.rb b/db/migrate/20150507024319_drop_ldap_auth_settings_from_aacs.rb index f6711921d9e..8856900ecd9 100644 --- a/db/migrate/20150507024319_drop_ldap_auth_settings_from_aacs.rb +++ b/db/migrate/20150507024319_drop_ldap_auth_settings_from_aacs.rb @@ -19,8 +19,10 @@ class DropLdapAuthSettingsFromAacs < ActiveRecord::Migration[4.2] tag :postdeploy def up - remove_column :account_authorization_configs, :login_handle_name - remove_column :account_authorization_configs, :change_password_url + AuthenticationProvider.maybe_recreate_view do + remove_column :account_authorization_configs, :login_handle_name + remove_column :account_authorization_configs, :change_password_url + end end def down diff --git a/db/migrate/20150520141519_populate_unknown_user_url.rb b/db/migrate/20150520141519_populate_unknown_user_url.rb index ebf339250a6..d6677b863af 100644 --- a/db/migrate/20150520141519_populate_unknown_user_url.rb +++ b/db/migrate/20150520141519_populate_unknown_user_url.rb @@ -18,10 +18,16 @@ class PopulateUnknownUserUrl < ActiveRecord::Migration[4.2] tag :predeploy + class AuthenticationProvider < ActiveRecord::Base + self.table_name = 'account_authorization_configs' + + belongs_to :account + end + def up - AccountAuthorizationConfig.select("*, unknown_user_url AS uuu").find_each do |aac| + AuthenticationProvider.select("*, unknown_user_url AS uuu").find_each do |aac| account = aac.account - if !account.unknown_user_url.present? && aac['uuu'].present? + if account.unknown_user_url.blank? && aac['uuu'].present? account.unknown_user_url = aac['uuu'] account.save! end diff --git a/db/migrate/20150520143503_drop_unknown_user_url_from_account_authorization_configs.rb b/db/migrate/20150520143503_drop_unknown_user_url_from_account_authorization_configs.rb index 7a2dff6648f..0d5d3893fb9 100644 --- a/db/migrate/20150520143503_drop_unknown_user_url_from_account_authorization_configs.rb +++ b/db/migrate/20150520143503_drop_unknown_user_url_from_account_authorization_configs.rb @@ -19,7 +19,9 @@ class DropUnknownUserUrlFromAccountAuthorizationConfigs < ActiveRecord::Migratio tag :postdeploy def up - remove_column :account_authorization_configs, :unknown_user_url + AuthenticationProvider.maybe_recreate_view do + remove_column :account_authorization_configs, :unknown_user_url + end end def down diff --git a/db/migrate/20150825233217_grandfather_canvas_authentication.rb b/db/migrate/20150825233217_grandfather_canvas_authentication.rb index bde2f5d69c3..b6ff894b996 100644 --- a/db/migrate/20150825233217_grandfather_canvas_authentication.rb +++ b/db/migrate/20150825233217_grandfather_canvas_authentication.rb @@ -20,7 +20,7 @@ class GrandfatherCanvasAuthentication < ActiveRecord::Migration[4.2] disable_ddl_transaction! def up - AccountAuthorizationConfig::Canvas.reset_column_information + AuthenticationProvider::Canvas.reset_column_information Account.root_accounts.each do |account| if account.settings[:canvas_authentication] != false || !account.authentication_providers.active.exists? account.enable_canvas_authentication @@ -29,6 +29,6 @@ class GrandfatherCanvasAuthentication < ActiveRecord::Migration[4.2] end def down - AccountAuthorizationConfig.where(auth_type: 'canvas').delete_all + AuthenticationProvider.where(auth_type: 'canvas').delete_all end end diff --git a/db/migrate/20150925063254_change_auth_filter_to_text.rb b/db/migrate/20150925063254_change_auth_filter_to_text.rb index 384c6b244a3..7f0ef65ad7e 100644 --- a/db/migrate/20150925063254_change_auth_filter_to_text.rb +++ b/db/migrate/20150925063254_change_auth_filter_to_text.rb @@ -19,7 +19,9 @@ class ChangeAuthFilterToText < ActiveRecord::Migration[4.2] tag :postdeploy def self.up - change_column :account_authorization_configs, :auth_filter, :text + AuthenticationProvider.maybe_recreate_view do + change_column :account_authorization_configs, :auth_filter, :text + end end def self.down diff --git a/db/migrate/20160607214646_move_saml_entity_id_to_account.rb b/db/migrate/20160607214646_move_saml_entity_id_to_account.rb index ff0431e259d..71cdb9bf256 100644 --- a/db/migrate/20160607214646_move_saml_entity_id_to_account.rb +++ b/db/migrate/20160607214646_move_saml_entity_id_to_account.rb @@ -18,8 +18,12 @@ class MoveSamlEntityIdToAccount < ActiveRecord::Migration[4.2] tag :postdeploy + class AuthenticationProvider < ActiveRecord::Base + self.table_name = 'account_authorization_configs' + end + def up - AccountAuthorizationConfig::SAML.active.where.not(entity_id: nil).each do |ap| + AuthenticationProvider.where(workflow_state: 'active', auth_type: 'saml').where.not(entity_id: nil).each do |ap| ap.account.settings[:saml_entity_id] ||= ap.entity_id ap.account.save! end diff --git a/db/migrate/20161206165139_add_back_default_string_limits_p1.rb b/db/migrate/20161206165139_add_back_default_string_limits_p1.rb index f12e8abc02a..e0598e6c47f 100644 --- a/db/migrate/20161206165139_add_back_default_string_limits_p1.rb +++ b/db/migrate/20161206165139_add_back_default_string_limits_p1.rb @@ -29,21 +29,23 @@ class AddBackDefaultStringLimitsP1 < ActiveRecord::Migration[4.2] add_string_limit_if_missing :access_tokens, :token_hint add_string_limit_if_missing :access_tokens, :crypted_refresh_token - add_string_limit_if_missing :account_authorization_configs, :auth_host - add_string_limit_if_missing :account_authorization_configs, :auth_base - add_string_limit_if_missing :account_authorization_configs, :auth_username - add_string_limit_if_missing :account_authorization_configs, :auth_crypted_password - add_string_limit_if_missing :account_authorization_configs, :auth_password_salt - add_string_limit_if_missing :account_authorization_configs, :auth_type - add_string_limit_if_missing :account_authorization_configs, :auth_over_tls - add_string_limit_if_missing :account_authorization_configs, :log_in_url - add_string_limit_if_missing :account_authorization_configs, :log_out_url - add_string_limit_if_missing :account_authorization_configs, :identifier_format - add_string_limit_if_missing :account_authorization_configs, :entity_id - add_string_limit_if_missing :account_authorization_configs, :requested_authn_context - add_string_limit_if_missing :account_authorization_configs, :idp_entity_id - add_string_limit_if_missing :account_authorization_configs, :workflow_state - add_string_limit_if_missing :account_authorization_configs, :metadata_uri + AuthenticationProvider.maybe_recreate_view do + add_string_limit_if_missing :account_authorization_configs, :auth_host + add_string_limit_if_missing :account_authorization_configs, :auth_base + add_string_limit_if_missing :account_authorization_configs, :auth_username + add_string_limit_if_missing :account_authorization_configs, :auth_crypted_password + add_string_limit_if_missing :account_authorization_configs, :auth_password_salt + add_string_limit_if_missing :account_authorization_configs, :auth_type + add_string_limit_if_missing :account_authorization_configs, :auth_over_tls + add_string_limit_if_missing :account_authorization_configs, :log_in_url + add_string_limit_if_missing :account_authorization_configs, :log_out_url + add_string_limit_if_missing :account_authorization_configs, :identifier_format + add_string_limit_if_missing :account_authorization_configs, :entity_id + add_string_limit_if_missing :account_authorization_configs, :requested_authn_context + add_string_limit_if_missing :account_authorization_configs, :idp_entity_id + add_string_limit_if_missing :account_authorization_configs, :workflow_state + add_string_limit_if_missing :account_authorization_configs, :metadata_uri + end add_string_limit_if_missing :account_notifications, :subject add_string_limit_if_missing :account_notifications, :icon diff --git a/db/migrate/20170526160229_fix_empty_hosted_domain_for_google.rb b/db/migrate/20170526160229_fix_empty_hosted_domain_for_google.rb index 6eafec65608..a42e6036881 100644 --- a/db/migrate/20170526160229_fix_empty_hosted_domain_for_google.rb +++ b/db/migrate/20170526160229_fix_empty_hosted_domain_for_google.rb @@ -18,11 +18,11 @@ class FixEmptyHostedDomainForGoogle < ActiveRecord::Migration[4.2] tag :postdeploy - def self.up - DataFixup::SetEmptyGoogleHostedDomainToNull.send_later_if_production_enqueue_args( - :run, { priority: Delayed::LOWER_PRIORITY, max_attempts: 1 }) + class AuthenticationProvider < ActiveRecord::Base + self.table_name = 'account_authorization_configs' end - def self.down + def self.up + AuthenticationProvider.where(auth_type: 'google', auth_filter: '').update_all(auth_filter: nil) end end diff --git a/db/migrate/20180312105014_disable_no_tls_for_ldap.rb b/db/migrate/20180312105014_disable_no_tls_for_ldap.rb index 9748721a089..be2abac36be 100644 --- a/db/migrate/20180312105014_disable_no_tls_for_ldap.rb +++ b/db/migrate/20180312105014_disable_no_tls_for_ldap.rb @@ -18,8 +18,16 @@ class DisableNoTlsForLdap < ActiveRecord::Migration[5.0] tag :postdeploy + class AuthenticationProvider < ActiveRecord::Base + self.table_name = 'account_authorization_configs' + + def auth_over_tls + ::AuthenticationProvider::LDAP.auth_over_tls_setting(read_attribute(:auth_over_tls)) + end + end + def up - AccountAuthorizationConfig::LDAP.active.each do |ap| + AuthenticationProvider.where(auth_type: 'ldap', workflow_state: 'active').each do |ap| ap.update_attribute(:auth_over_tls, 'start_tls') unless ap.auth_over_tls end end diff --git a/lib/data_fixup/set_empty_google_hosted_domain_to_null.rb b/db/migrate/20180424211010_create_authentication_providers_view.rb similarity index 60% rename from lib/data_fixup/set_empty_google_hosted_domain_to_null.rb rename to db/migrate/20180424211010_create_authentication_providers_view.rb index 01955e7baf1..d963c4bbab7 100644 --- a/lib/data_fixup/set_empty_google_hosted_domain_to_null.rb +++ b/db/migrate/20180424211010_create_authentication_providers_view.rb @@ -1,5 +1,5 @@ # -# Copyright (C) 2011 - present Instructure, Inc. +# Copyright (C) 2018 - present Instructure, Inc. # # This file is part of Canvas. # @@ -16,8 +16,14 @@ # with this program. If not, see . # -module DataFixup::SetEmptyGoogleHostedDomainToNull - def self.run - AccountAuthorizationConfig::Google.where(auth_filter: '').update_all(auth_filter: nil) +class CreateAuthenticationProvidersView < ActiveRecord::Migration[5.1] + tag :predeploy + + def up + execute("CREATE VIEW #{connection.quote_table_name('authentication_providers')} AS SELECT * FROM #{connection.quote_table_name('account_authorization_configs')}") + end + + def down + execute("DROP VIEW #{connection.quote_table_name('authentication_providers')}") end end diff --git a/db/migrate/20180425185812_rename_account_authorization_configs_to_authentication_providers.rb b/db/migrate/20180425185812_rename_account_authorization_configs_to_authentication_providers.rb new file mode 100644 index 00000000000..eea9f727146 --- /dev/null +++ b/db/migrate/20180425185812_rename_account_authorization_configs_to_authentication_providers.rb @@ -0,0 +1,30 @@ +# +# Copyright (C) 2018 - present Instructure, Inc. +# +# This file is part of Canvas. +# +# Canvas is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the Free +# Software Foundation, version 3 of the License. +# +# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see . + +class RenameAccountAuthorizationConfigsToAuthenticationProviders < ActiveRecord::Migration[5.1] + tag :postdeploy + + def up + execute("DROP VIEW #{connection.quote_table_name('authentication_providers')}") + rename_table :account_authorization_configs, :authentication_providers + end + + def down + rename_table :authentication_providers, :account_authorization_configs + execute("CREATE VIEW #{connection.quote_table_name('authentication_providers')} AS SELECT * FROM #{connection.quote_table_name('account_authorization_configs')}") + end +end diff --git a/doc/api/fulldoc/html/swagger/object_view.rb b/doc/api/fulldoc/html/swagger/object_view.rb index f7c12b850b4..12a3f89da2b 100644 --- a/doc/api/fulldoc/html/swagger/object_view.rb +++ b/doc/api/fulldoc/html/swagger/object_view.rb @@ -50,7 +50,7 @@ class ObjectView < HashView end # Some @object descriptions have multiple JSON parts. - # See e.g. AccountAuthorizationConfig + # See e.g. AuthenticationProvider def clean_json_text_parts clean_json_text.gsub(/(\})\s+(\{)/, "\\1#{SEP}\\2").split(SEP) end @@ -76,4 +76,4 @@ class ObjectView < HashView def self.strip_comments(str) str.gsub(%r(//[^\n\"]+$), '') end -end \ No newline at end of file +end diff --git a/gems/rubocop-canvas/spec/rubocop/cop/specs/ensure_spec_extension_spec.rb b/gems/rubocop-canvas/spec/rubocop/cop/specs/ensure_spec_extension_spec.rb index 65b8ec8987c..d75eedd1a88 100644 --- a/gems/rubocop-canvas/spec/rubocop/cop/specs/ensure_spec_extension_spec.rb +++ b/gems/rubocop-canvas/spec/rubocop/cop/specs/ensure_spec_extension_spec.rb @@ -26,7 +26,7 @@ describe RuboCop::Cop::Specs::EnsureSpecExtension do context "top level context" do it 'does not warn for *_spec.rb extension' do inspect_source(%{ - context AccountAuthorizationConfig::BlueDragoon do + context AuthenticationProvider::BlueDragoon do describe '#fire' do it 'rains fire' do expect(1).to eq(1) @@ -41,7 +41,7 @@ describe RuboCop::Cop::Specs::EnsureSpecExtension do context "top level describe" do it 'does not warn for *_spec.rb extension' do inspect_source(%{ - describe AccountAuthorizationConfig::GreenDragoon do + describe AuthenticationProvider::GreenDragoon do describe '#green' do it 'smells bad' do expect(1).to eq(1) @@ -62,7 +62,7 @@ describe RuboCop::Cop::Specs::EnsureSpecExtension do context "top level context" do it 'warns for *_spec.rb extension' do inspect_source(%{ - context AccountAuthorizationConfig::BlueDragoon do + context AuthenticationProvider::BlueDragoon do describe '#fire' do it 'rains fire' do expect(1).to eq(1) @@ -79,7 +79,7 @@ describe RuboCop::Cop::Specs::EnsureSpecExtension do context "top level describe" do it 'warns for *_spec.rb extension' do inspect_source(%{ - describe AccountAuthorizationConfig::GreenDragoon do + describe AuthenticationProvider::GreenDragoon do describe '#green' do it 'smells bad' do expect(1).to eq(1) diff --git a/gems/tatl_tael/spec/lib/tatl_tael/linters/shared_constants.rb b/gems/tatl_tael/spec/lib/tatl_tael/linters/shared_constants.rb index 041ff5fefc6..0289fc4c89c 100644 --- a/gems/tatl_tael/spec/lib/tatl_tael/linters/shared_constants.rb +++ b/gems/tatl_tael/spec/lib/tatl_tael/linters/shared_constants.rb @@ -1,6 +1,6 @@ module Consts APP_COFFEE_PATH = "app/coffeescripts/calendar/CalendarEvent.coffee".freeze - APP_COFFEE_BUNDLE_PATH = "app/coffeescripts/bundles/account_authorization_configs.coffee".freeze + APP_COFFEE_BUNDLE_PATH = "app/coffeescripts/bundles/authentication_providers.coffee".freeze COFFEE_SPEC_PATH = "spec/coffeescripts/calendar/CalendarSpec.coffee".freeze APP_JSX_PATH = "app/jsx/dashboard_card/DashboardCardAction.js".freeze diff --git a/lib/api/v1/account_authorization_config.rb b/lib/api/v1/authentication_provider.rb similarity index 97% rename from lib/api/v1/account_authorization_config.rb rename to lib/api/v1/authentication_provider.rb index 94092f64039..b0ef4cf1cb9 100644 --- a/lib/api/v1/account_authorization_config.rb +++ b/lib/api/v1/authentication_provider.rb @@ -16,7 +16,7 @@ # with this program. If not, see . # -module Api::V1::AccountAuthorizationConfig +module Api::V1::AuthenticationProvider include Api::V1::Json def aacs_json(aacs) diff --git a/lib/canvas/security.rb b/lib/canvas/security.rb index 9889634294f..e19906331b3 100644 --- a/lib/canvas/security.rb +++ b/lib/canvas/security.rb @@ -211,26 +211,29 @@ module Canvas::Security def self.re_encrypt_data(encryption_key) { Account => { - :encrypted_column => :turnitin_crypted_secret, - :salt_column => :turnitin_salt, - :key => 'instructure_turnitin_secret_shared' }, - AccountAuthorizationConfig => { - :encrypted_column => :auth_crypted_password, - :salt_column => :auth_password_salt, - :key => 'instructure_auth' }, + :encrypted_column => :turnitin_crypted_secret, + :salt_column => :turnitin_salt, + :key => 'instructure_turnitin_secret_shared' + }, + AuthenticationProvider => { + :encrypted_column => :auth_crypted_password, + :salt_column => :auth_password_salt, + :key => 'instructure_auth' + }, UserService => { - :encrypted_column => :crypted_password, - :salt_column => :password_salt, - :key => 'instructure_user_service' }, + :encrypted_column => :crypted_password, + :salt_column => :password_salt, + :key => 'instructure_user_service' + }, User => { - :encrypted_column => :otp_secret_key_enc, - :salt_column => :otp_secret_key_salt, - :key => 'otp_secret_key' + :encrypted_column => :otp_secret_key_enc, + :salt_column => :otp_secret_key_salt, + :key => 'otp_secret_key' } }.each do |(model, definition)| model.where("#{definition[:encrypted_column]} IS NOT NULL"). - select([:id, definition[:encrypted_column], definition[:salt_column]]). - find_each do |instance| + select([:id, definition[:encrypted_column], definition[:salt_column]]). + find_each do |instance| cleartext = Canvas::Security.decrypt_password(instance.read_attribute(definition[:encrypted_column]), instance.read_attribute(definition[:salt_column]), definition[:key], diff --git a/lib/data_fixup/populate_account_auth_settings.rb b/lib/data_fixup/populate_account_auth_settings.rb index ec9359d7550..5a2971b91e5 100644 --- a/lib/data_fixup/populate_account_auth_settings.rb +++ b/lib/data_fixup/populate_account_auth_settings.rb @@ -16,15 +16,24 @@ # with this program. If not, see . module DataFixup::PopulateAccountAuthSettings + class AuthenticationProvider < ActiveRecord::Base + belongs_to :account + end def self.run - AccountAuthorizationConfig.select("*, login_handle_name AS lhn, change_password_url AS cpu").find_each do |aac| + AuthenticationProvider.table_name = if AuthenticationProvider.connection.table_exists?('account_authorization_configs') + 'account_authorization_configs' + else + 'authentication_providers' + end + + AuthenticationProvider.select("*, login_handle_name AS lhn, change_password_url AS cpu").find_each do |aac| account = aac.account - if !account.login_handle_name.present? && aac['lhn'].present? + if account.login_handle_name.blank? && aac['lhn'].present? account.login_handle_name = aac['lhn'] end - if !account.change_password_url.present? && aac['cpu'].present? + if account.change_password_url.blank? && aac['cpu'].present? account.change_password_url = aac['cpu'] end account.save! diff --git a/public/javascripts/account_authorization_configs.js b/public/javascripts/account_authorization_configs.js index 1752185496e..ec5494733fe 100644 --- a/public/javascripts/account_authorization_configs.js +++ b/public/javascripts/account_authorization_configs.js @@ -16,7 +16,7 @@ * with this program. If not, see . */ -import I18n from 'i18n!account_authorization_configs' +import I18n from 'i18n!authentication_providers' import htmlEscape from './str/htmlEscape' import React from 'react' import ReactDOM from 'react-dom' diff --git a/spec/apis/auth_spec.rb b/spec/apis/auth_spec.rb index 191a43d999a..ef1e2955f4d 100644 --- a/spec/apis/auth_spec.rb +++ b/spec/apis/auth_spec.rb @@ -190,7 +190,7 @@ describe "API Authentication", type: :request do end it "should execute for saml login" do - skip("requires SAML extension") unless AccountAuthorizationConfig::SAML.enabled? + skip("requires SAML extension") unless AuthenticationProvider::SAML.enabled? account_with_saml(account: Account.default) flow do allow_any_instance_of(Onelogin::Saml::Response).to receive(:settings=) diff --git a/spec/apis/v1/authentication_providers_api_spec.rb b/spec/apis/v1/authentication_providers_api_spec.rb index 0694eb2ad1a..4816953a5f9 100644 --- a/spec/apis/v1/authentication_providers_api_spec.rb +++ b/spec/apis/v1/authentication_providers_api_spec.rb @@ -46,7 +46,7 @@ describe "AuthenticationProviders API", type: :request do context "/index" do def call_index(status=200) api_call(:get, "/api/v1/accounts/#{@account.id}/authentication_providers", - { :controller => 'account_authorization_configs', :action => 'index', :account_id => @account.id.to_s, :format => 'json' }, + { :controller => 'authentication_providers', :action => 'index', :account_id => @account.id.to_s, :format => 'json' }, {}, {}, :expected_status => status) end @@ -73,7 +73,7 @@ describe "AuthenticationProviders API", type: :request do def call_create(params, status = 200) json = api_call(:post, "/api/v1/accounts/#{@account.id}/authentication_providers", - { :controller => 'account_authorization_configs', :action => 'create', :account_id => @account.id.to_s, :format => 'json' }, + { :controller => 'authentication_providers', :action => 'create', :account_id => @account.id.to_s, :format => 'json' }, params, {}, :expected_status => status) @account.reload json @@ -165,7 +165,11 @@ describe "AuthenticationProviders API", type: :request do it "should error if empty post params sent" do json = call_create({}, 422) - expect(json['errors'].first).to eq({ 'field' => 'auth_type', 'message' => "invalid auth_type, must be one of #{AccountAuthorizationConfig::VALID_AUTH_TYPES.join(',')}", 'error_code' => 'inclusion' }) + expect(json['errors'].first).to eq({ + 'field' => 'auth_type', + 'message' => "invalid auth_type, must be one of #{AuthenticationProvider::VALID_AUTH_TYPES.join(',')}", + 'error_code' => 'inclusion' + }) end it "should return unauthorized error" do @@ -189,7 +193,7 @@ describe "AuthenticationProviders API", type: :request do context "/show" do def call_show(id, status = 200) api_call(:get, "/api/v1/accounts/#{@account.id}/authentication_providers/#{id}", - { :controller => 'account_authorization_configs', :action => 'show', :account_id => @account.id.to_s, :id => id.to_param, :format => 'json' }, + { :controller => 'authentication_providers', :action => 'show', :account_id => @account.id.to_s, :id => id.to_param, :format => 'json' }, {}, {}, :expected_status => status) end @@ -248,7 +252,7 @@ describe "AuthenticationProviders API", type: :request do context "/update" do def call_update(id, params, status = 200) json = api_call(:put, "/api/v1/accounts/#{@account.id}/authentication_providers/#{id}", - { :controller => 'account_authorization_configs', :action => 'update', :account_id => @account.id.to_s, :id => id.to_param, :format => 'json' }, + { :controller => 'authentication_providers', :action => 'update', :account_id => @account.id.to_s, :id => id.to_param, :format => 'json' }, params, {}, :expected_status => status) @account.reload json @@ -338,7 +342,7 @@ describe "AuthenticationProviders API", type: :request do context "/destroy" do def call_destroy(id, status = 200) json = api_call(:delete, "/api/v1/accounts/#{@account.id}/authentication_providers/#{id}", - { :controller => 'account_authorization_configs', :action => 'destroy', :account_id => @account.id.to_s, :id => id.to_param, :format => 'json' }, + { :controller => 'authentication_providers', :action => 'destroy', :account_id => @account.id.to_s, :id => id.to_param, :format => 'json' }, {}, {}, :expected_status => status) @account.reload json @@ -395,7 +399,7 @@ describe "AuthenticationProviders API", type: :request do api_call(:put, sso_path, { - controller: 'account_authorization_configs', + controller: 'authentication_providers', action: 'update_sso_settings', account_id: @account.id.to_s, format: 'json' @@ -459,7 +463,7 @@ describe "AuthenticationProviders API", type: :request do response = api_call(:get, sso_path, { - controller: "account_authorization_configs", + controller: "authentication_providers", action: "show_sso_settings", account_id: @account.id.to_s, format: 'json' @@ -475,10 +479,11 @@ describe "AuthenticationProviders API", type: :request do describe "API JSON" do describe 'federated_attributes' do it 'excludes provisioning only attributes when jit_provisioning is off' do - aac = AccountAuthorizationConfig::SAML.new( + aac = AuthenticationProvider::SAML.new( federated_attributes: { 'integration_id' => { 'attribute' => 'internal_id' }, 'sis_user_id' => { 'attribute' => 'external_id', - 'provisioning_only' => true }}) + 'provisioning_only' => true }} + ) expect(aac.federated_attributes_for_api).to eq('integration_id' => 'internal_id') end @@ -487,7 +492,7 @@ describe "AuthenticationProviders API", type: :request do 'provisioning_only' => false }, 'sis_user_id' => { 'attribute' => 'external_id', 'provisioning_only' => true }} - aac = AccountAuthorizationConfig::SAML.new(federated_attributes: federated_attributes, + aac = AuthenticationProvider::SAML.new(federated_attributes: federated_attributes, jit_provisioning: true) expect(aac.federated_attributes_for_api).to eq(federated_attributes) end diff --git a/spec/controllers/account_authorization_configs_controller_spec.rb b/spec/controllers/authentication_providers_controller_spec.rb similarity index 99% rename from spec/controllers/account_authorization_configs_controller_spec.rb rename to spec/controllers/authentication_providers_controller_spec.rb index 746f3c36530..a4017bd94b2 100644 --- a/spec/controllers/account_authorization_configs_controller_spec.rb +++ b/spec/controllers/authentication_providers_controller_spec.rb @@ -18,7 +18,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') -describe AccountAuthorizationConfigsController do +describe AuthenticationProvidersController do let!(:account) { Account.create! } diff --git a/spec/controllers/login/cas_controller_spec.rb b/spec/controllers/login/cas_controller_spec.rb index 2489cb577d1..a7ce9382810 100644 --- a/spec/controllers/login/cas_controller_spec.rb +++ b/spec/controllers/login/cas_controller_spec.rb @@ -29,7 +29,7 @@ describe Login::CasController do st.success = response.is_success? st end - allow_any_instance_of(AccountAuthorizationConfig::CAS).to receive(:client).and_return(cas_client) if use_mock + allow_any_instance_of(AuthenticationProvider::CAS).to receive(:client).and_return(cas_client) if use_mock end it "should logout with specific cas ticket" do diff --git a/spec/controllers/login/saml_controller_spec.rb b/spec/controllers/login/saml_controller_spec.rb index e9bf6f09731..75f189ee847 100644 --- a/spec/controllers/login/saml_controller_spec.rb +++ b/spec/controllers/login/saml_controller_spec.rb @@ -20,7 +20,7 @@ require_relative '../../spec_helper' describe Login::SamlController do before do - skip("requires SAML extension") unless AccountAuthorizationConfig::SAML.enabled? + skip("requires SAML extension") unless AuthenticationProvider::SAML.enabled? end it "should scope logins to the correct domain root account" do diff --git a/spec/factories/account_factory.rb b/spec/factories/account_factory.rb index 4de7a85c455..e36177ba81d 100644 --- a/spec/factories/account_factory.rb +++ b/spec/factories/account_factory.rb @@ -64,7 +64,7 @@ module Factories def account_with_cas(opts={}) @account = opts[:account] @account ||= Account.create! - config = AccountAuthorizationConfig::CAS.new + config = AuthenticationProvider::CAS.new cas_url = opts[:cas_url] || "https://localhost/cas" config.auth_type = "cas" config.auth_base = cas_url @@ -77,7 +77,7 @@ module Factories def account_with_saml(opts={}) @account = opts[:account] @account ||= Account.create! - config = AccountAuthorizationConfig::SAML.new + config = AuthenticationProvider::SAML.new config.idp_entity_id = "saml_entity" config.auth_type = "saml" config.log_in_url = opts[:saml_log_in_url] if opts[:saml_log_in_url] diff --git a/spec/integration/account_spec.rb b/spec/integration/account_spec.rb index f2e0ad13c84..01a80721056 100644 --- a/spec/integration/account_spec.rb +++ b/spec/integration/account_spec.rb @@ -24,7 +24,7 @@ describe AccountsController do context "SAML meta data" do before(:each) do - skip("requires SAML extension") unless AccountAuthorizationConfig::SAML.enabled? + skip("requires SAML extension") unless AuthenticationProvider::SAML.enabled? @account = Account.create!(:name => "test") end diff --git a/spec/integration/login_spec.rb b/spec/integration/login_spec.rb index 0096fca2536..7eff15b5610 100644 --- a/spec/integration/login_spec.rb +++ b/spec/integration/login_spec.rb @@ -244,7 +244,7 @@ describe 'login' do context "SAML" do before do - skip("requires SAML extension") unless AccountAuthorizationConfig::SAML.enabled? + skip("requires SAML extension") unless AuthenticationProvider::SAML.enabled? end it 'redirects to the discovery page when hitting a deep link while unauthenticated' do diff --git a/spec/lib/acts_as_list_spec.rb b/spec/lib/acts_as_list_spec.rb index d19e404a304..68f62c1d0e7 100644 --- a/spec/lib/acts_as_list_spec.rb +++ b/spec/lib/acts_as_list_spec.rb @@ -103,8 +103,8 @@ describe "acts_as_list" do describe "base scope" do it "scopes by the base class rather then the STI class" do - scope = AccountAuthorizationConfig::CAS.new.list_scope_base - expect(scope.to_sql).to_not(match(/auth_type/)) + scope = AuthenticationProvider::CAS.new.list_scope_base + expect(scope.to_sql).not_to(match(/auth_type/)) end end end diff --git a/spec/lib/api/v1/pseudonym_spec.rb b/spec/lib/api/v1/pseudonym_spec.rb index 174cc5d9522..1194784e0b2 100644 --- a/spec/lib/api/v1/pseudonym_spec.rb +++ b/spec/lib/api/v1/pseudonym_spec.rb @@ -29,7 +29,7 @@ describe "Api::V1::Pseudonym" do let(:api) { Harness.new } it "includes the authentication_provider_type if there is one" do - aac = AccountAuthorizationConfig.new(auth_type: "ldap") + aac = AuthenticationProvider.new(auth_type: "ldap") pseudonym.authentication_provider = aac json = api.pseudonym_json(pseudonym, user, session) expect(json[:authentication_provider_type]).to eq("ldap") diff --git a/spec/migrations/disable_open_registration_for_delegated_auth_spec.rb b/spec/migrations/disable_open_registration_for_delegated_auth_spec.rb deleted file mode 100644 index 7198c153c64..00000000000 --- a/spec/migrations/disable_open_registration_for_delegated_auth_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -# -# Copyright (C) 2011 - present Instructure, Inc. -# -# This file is part of Canvas. -# -# Canvas is free software: you can redistribute it and/or modify it under -# the terms of the GNU Affero General Public License as published by the Free -# Software Foundation, version 3 of the License. -# -# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more -# details. -# -# You should have received a copy of the GNU Affero General Public License along -# with this program. If not, see . -# - -require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') -require 'db/migrate/20111121175219_disable_open_registration_for_delegated_auth.rb' - -describe 'DisableOpenRegistrationForDelegatedAuth' do - describe "up" do - it "should work" do - @cas_account = Account.create! - @saml_account = Account.create! - @ldap_account = Account.create! - @normal_account = Account.create! - @all_accounts = [@cas_account, @saml_account, @ldap_account, @normal_account] - @cas_account.authentication_providers.create!(:auth_type => 'cas') - @saml_account.authentication_providers.create!(:auth_type => 'saml') - @ldap_account.authentication_providers.create!(:auth_type => 'ldap') - @all_accounts.each do |account| - # have to bypass the settings= logic for weeding these out since they don't - # apply - account.write_attribute(:settings, { :open_registration => true }) - account.save! - expect(account.open_registration?).to be_truthy - end - - DisableOpenRegistrationForDelegatedAuth.up - - @all_accounts.each(&:reload) - expect(@cas_account.open_registration?).to be_falsey - expect(@saml_account.open_registration?).to be_falsey - expect(@ldap_account.open_registration?).to be_truthy - expect(@normal_account.open_registration?).to be_truthy - end - end -end diff --git a/spec/models/account_authorization_config/google_spec.rb b/spec/models/authentication_provider/google_spec.rb similarity index 88% rename from spec/models/account_authorization_config/google_spec.rb rename to spec/models/authentication_provider/google_spec.rb index 607fc607b65..ffa62c36e42 100644 --- a/spec/models/account_authorization_config/google_spec.rb +++ b/spec/models/authentication_provider/google_spec.rb @@ -18,9 +18,9 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') -describe AccountAuthorizationConfig::Google do +describe AuthenticationProvider::Google do it 'rejects non-matching hd' do - ap = AccountAuthorizationConfig::Google.new + ap = AuthenticationProvider::Google.new ap.hosted_domain = 'instructure.com' expect(Canvas::Security).to receive(:decode_jwt).and_return({'hd' => 'school.edu', 'sub' => '123'}) userinfo = double('userinfo', parsed: {}) @@ -30,7 +30,7 @@ describe AccountAuthorizationConfig::Google do end it 'rejects missing hd' do - ap = AccountAuthorizationConfig::Google.new + ap = AuthenticationProvider::Google.new ap.hosted_domain = 'instructure.com' expect(Canvas::Security).to receive(:decode_jwt).and_return({'sub' => '123'}) token = double('token', params: {}, options: {}) @@ -39,7 +39,7 @@ describe AccountAuthorizationConfig::Google do end it "accepts when hosted domain isn't required" do - ap = AccountAuthorizationConfig::Google.new + ap = AuthenticationProvider::Google.new expect(Canvas::Security).to receive(:decode_jwt).once.and_return({'sub' => '123'}) token = double('token', params: {}, options: {}) @@ -47,7 +47,7 @@ describe AccountAuthorizationConfig::Google do end it "it sets hosted domain to nil if empty string" do - ap = AccountAuthorizationConfig::Google.new + ap = AuthenticationProvider::Google.new ap.hosted_domain = '' expect(ap.hosted_domain).to be_nil end diff --git a/spec/models/account_authorization_config/ldap_spec.rb b/spec/models/authentication_provider/ldap_spec.rb similarity index 94% rename from spec/models/account_authorization_config/ldap_spec.rb rename to spec/models/authentication_provider/ldap_spec.rb index 1cd1e785d5b..d63fb2b9414 100644 --- a/spec/models/account_authorization_config/ldap_spec.rb +++ b/spec/models/authentication_provider/ldap_spec.rb @@ -18,7 +18,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') -describe AccountAuthorizationConfig::LDAP do +describe AuthenticationProvider::LDAP do it "should not escape auth_filter" do @account = Account.new @account_config = @account.authentication_providers.build( @@ -32,7 +32,7 @@ describe AccountAuthorizationConfig::LDAP do describe "#test_ldap_search" do it "should validate filter syntax" do - aac = AccountAuthorizationConfig::LDAP.new + aac = AuthenticationProvider::LDAP.new aac.auth_type = 'ldap' aac.ldap_filter = 'bob' expect(aac.test_ldap_search).to be_falsey @@ -49,14 +49,14 @@ describe AccountAuthorizationConfig::LDAP do before(:once) do @account = Account.new @account.save! - @aac = AccountAuthorizationConfig::LDAP.new(account: @account) + @aac = AuthenticationProvider::LDAP.new(account: @account) @aac.auth_type = 'ldap' @aac.ldap_filter = 'bob' @aac.save! end it "should not attempt to bind with a blank password" do - aac = AccountAuthorizationConfig::LDAP.new + aac = AuthenticationProvider::LDAP.new aac.auth_type = 'ldap' aac.ldap_filter = 'bob' expect(aac).to receive(:ldap_connection).never diff --git a/spec/models/account_authorization_config/open_id_connect_spec.rb b/spec/models/authentication_provider/open_id_connect_spec.rb similarity index 94% rename from spec/models/account_authorization_config/open_id_connect_spec.rb rename to spec/models/authentication_provider/open_id_connect_spec.rb index a925f0c6053..365451dab9d 100644 --- a/spec/models/account_authorization_config/open_id_connect_spec.rb +++ b/spec/models/authentication_provider/open_id_connect_spec.rb @@ -17,7 +17,7 @@ require_relative '../../spec_helper.rb' -describe AccountAuthorizationConfig::OpenIDConnect do +describe AuthenticationProvider::OpenIDConnect do describe '#scope_for_options' do it 'automatically infers according to requested claims' do @@ -62,7 +62,7 @@ describe AccountAuthorizationConfig::OpenIDConnect do describe "#user_logout_url" do it "returns the end_session_endpoint" do - ap = AccountAuthorizationConfig::OpenIDConnect.new(end_session_endpoint: "http://somewhere/logout") + ap = AuthenticationProvider::OpenIDConnect.new(end_session_endpoint: "http://somewhere/logout") expect(ap.user_logout_redirect(nil, nil)).to eq "http://somewhere/logout" end end diff --git a/spec/models/account_authorization_config/plugin_settings_spec.rb b/spec/models/authentication_provider/plugin_settings_spec.rb similarity index 94% rename from spec/models/account_authorization_config/plugin_settings_spec.rb rename to spec/models/authentication_provider/plugin_settings_spec.rb index 2cfdcd43bd5..6901f4b0a12 100644 --- a/spec/models/account_authorization_config/plugin_settings_spec.rb +++ b/spec/models/authentication_provider/plugin_settings_spec.rb @@ -18,10 +18,10 @@ require_relative '../../spec_helper.rb' -describe AccountAuthorizationConfig::PluginSettings do +describe AuthenticationProvider::PluginSettings do let(:klass) do - Class.new(AccountAuthorizationConfig) do - include AccountAuthorizationConfig::PluginSettings + Class.new(AuthenticationProvider) do + include AuthenticationProvider::PluginSettings self.plugin = :custom_plugin def noninherited_method diff --git a/spec/models/account_authorization_config/saml/in_common_spec.rb b/spec/models/authentication_provider/saml/in_common_spec.rb similarity index 93% rename from spec/models/account_authorization_config/saml/in_common_spec.rb rename to spec/models/authentication_provider/saml/in_common_spec.rb index 24a2f84dc2a..cfc5e98361e 100644 --- a/spec/models/account_authorization_config/saml/in_common_spec.rb +++ b/spec/models/authentication_provider/saml/in_common_spec.rb @@ -18,12 +18,12 @@ require_relative '../../../spec_helper' -describe AccountAuthorizationConfig::SAML::InCommon do - let(:subject) { AccountAuthorizationConfig::SAML::InCommon } +describe AuthenticationProvider::SAML::InCommon do + let(:subject) { AuthenticationProvider::SAML::InCommon } describe ".refresh_providers" do before do - allow_any_instance_of(AccountAuthorizationConfig::SAML).to receive(:download_metadata).and_return(nil) + allow_any_instance_of(AuthenticationProvider::SAML).to receive(:download_metadata).and_return(nil) end let!(:saml) { Account.default.authentication_providers.create!(auth_type: 'saml', diff --git a/spec/models/account_authorization_config/saml/metadata_refresher_spec.rb b/spec/models/authentication_provider/saml/metadata_refresher_spec.rb similarity index 88% rename from spec/models/account_authorization_config/saml/metadata_refresher_spec.rb rename to spec/models/authentication_provider/saml/metadata_refresher_spec.rb index c5812a6d3e7..eed8e93427a 100644 --- a/spec/models/account_authorization_config/saml/metadata_refresher_spec.rb +++ b/spec/models/authentication_provider/saml/metadata_refresher_spec.rb @@ -18,15 +18,15 @@ require_relative '../../../spec_helper' -describe AccountAuthorizationConfig::SAML::MetadataRefresher do - let(:subject) { AccountAuthorizationConfig::SAML::MetadataRefresher } +describe AuthenticationProvider::SAML::MetadataRefresher do + let(:subject) { AuthenticationProvider::SAML::MetadataRefresher } describe ".refresh_providers" do before do - allow_any_instance_of(AccountAuthorizationConfig::SAML).to receive(:download_metadata).and_return(nil) + allow_any_instance_of(AuthenticationProvider::SAML).to receive(:download_metadata).and_return(nil) end - let (:saml1) { Account.default.authentication_providers.create!(auth_type: 'saml', metadata_uri: '1') } + let(:saml1) { Account.default.authentication_providers.create!(auth_type: 'saml', metadata_uri: '1') } it "keeps going even if one fails" do saml2 = Account.default.authentication_providers.create!(auth_type: 'saml', metadata_uri: '2') @@ -63,8 +63,8 @@ describe AccountAuthorizationConfig::SAML::MetadataRefresher do end it "ignores nil/blank metadata_uris" do - AccountAuthorizationConfig::SAML.where(id: saml1.id).update_all(metadata_uri: nil) - saml2 = Account.default.authentication_providers.create!(auth_type: 'saml', metadata_uri: '') + AuthenticationProvider::SAML.where(id: saml1.id).update_all(metadata_uri: nil) + Account.default.authentication_providers.create!(auth_type: 'saml', metadata_uri: '') expect(subject).to receive(:refresh_if_necessary).never subject.refresh_providers diff --git a/spec/models/account_authorization_config/saml_spec.rb b/spec/models/authentication_provider/saml_spec.rb similarity index 88% rename from spec/models/account_authorization_config/saml_spec.rb rename to spec/models/authentication_provider/saml_spec.rb index bfb95c5133d..ccfa76c161d 100644 --- a/spec/models/account_authorization_config/saml_spec.rb +++ b/spec/models/authentication_provider/saml_spec.rb @@ -18,9 +18,9 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') -describe AccountAuthorizationConfig::SAML do +describe AuthenticationProvider::SAML do before(:each) do - skip("requires SAML extension") unless AccountAuthorizationConfig::SAML.enabled? + skip("requires SAML extension") unless AuthenticationProvider::SAML.enabled? @account = Account.create!(:name => "account") @file_that_exists = File.expand_path(__FILE__) end @@ -36,7 +36,7 @@ describe AccountAuthorizationConfig::SAML do s = @account.authentication_providers.build(:auth_type => 'saml').saml_settings - expect(s.encryption_configured?).to be_truthy + expect(s).to be_encryption_configured end it "should load the tech contact settings" do @@ -115,21 +115,21 @@ describe AccountAuthorizationConfig::SAML do describe "download_metadata" do it 'requires an entity id for InCommon' do saml = Account.default.authentication_providers.new(auth_type: 'saml', - metadata_uri: AccountAuthorizationConfig::SAML::InCommon::URN) + metadata_uri: AuthenticationProvider::SAML::InCommon::URN) expect(saml).not_to be_valid expect(saml.errors.first.first).to eq :idp_entity_id end it 'changes InCommon URI to the URN for it' do saml = Account.default.authentication_providers.new(auth_type: 'saml', - metadata_uri: AccountAuthorizationConfig::SAML::InCommon.endpoint) + metadata_uri: AuthenticationProvider::SAML::InCommon.endpoint) expect(saml).not_to be_valid - expect(saml.metadata_uri).to eq AccountAuthorizationConfig::SAML::InCommon::URN + expect(saml.metadata_uri).to eq AuthenticationProvider::SAML::InCommon::URN end it "overwrite sig_alg field as appropriate" do # defaults to RSA-SHA256 - saml = AccountAuthorizationConfig::SAML.new + saml = AuthenticationProvider::SAML.new expect(saml.sig_alg).to eq SAML2::Bindings::HTTPRedirect::SigAlgs::RSA_SHA256 entity = SAML2::Entity.new @@ -159,21 +159,21 @@ describe AccountAuthorizationConfig::SAML do describe '.resolve_saml_key_path' do it "returns nil for nil" do - expect(AccountAuthorizationConfig::SAML.resolve_saml_key_path(nil)).to be_nil + expect(AuthenticationProvider::SAML.resolve_saml_key_path(nil)).to be_nil end it "returns nil for nonexistent paths" do - expect(AccountAuthorizationConfig::SAML.resolve_saml_key_path('/tmp/does_not_exist')).to be_nil + expect(AuthenticationProvider::SAML.resolve_saml_key_path('/tmp/does_not_exist')).to be_nil end it "returns abolute paths unmodified when the file exists" do Tempfile.open('samlkey') do |samlkey| - expect(AccountAuthorizationConfig::SAML.resolve_saml_key_path(samlkey.path)).to eq samlkey.path + expect(AuthenticationProvider::SAML.resolve_saml_key_path(samlkey.path)).to eq samlkey.path end end it "interprets relative paths from the config dir" do - expect(AccountAuthorizationConfig::SAML.resolve_saml_key_path('initializers')).to eq Rails.root.join('config', 'initializers').to_s + expect(AuthenticationProvider::SAML.resolve_saml_key_path('initializers')).to eq Rails.root.join('config', 'initializers').to_s end end @@ -203,7 +203,9 @@ describe AccountAuthorizationConfig::SAML do ap = @account.authentication_providers.build(:auth_type => 'saml') ap.federated_attributes = { 'display_name' => { 'attribute' => 'name' } } ap.save! - entity = AccountAuthorizationConfig::SAML.sp_metadata_for_account(@account) + # ignore invalid saml key configuration in specs + allow(AuthenticationProvider::SAML).to receive(:private_keys).and_return({}) + entity = AuthenticationProvider::SAML.sp_metadata_for_account(@account) expect(entity.roles.last.attribute_consuming_services.length).to eq 1 expect(entity.roles.last.attribute_consuming_services.first.requested_attributes.length). to eq 1 expect(entity.roles.last.attribute_consuming_services.first.requested_attributes.first.name). to eq 'name' diff --git a/spec/models/account_authorization_config_spec.rb b/spec/models/authentication_provider_spec.rb similarity index 90% rename from spec/models/account_authorization_config_spec.rb rename to spec/models/authentication_provider_spec.rb index e8c999ff4b4..3d95fddc5f5 100644 --- a/spec/models/account_authorization_config_spec.rb +++ b/spec/models/authentication_provider_spec.rb @@ -18,13 +18,13 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') -describe AccountAuthorizationConfig do +describe AuthenticationProvider do let(:account){ Account.default } context "password" do it "should decrypt the password to the original value" do - c = AccountAuthorizationConfig.new + c = AuthenticationProvider.new c.auth_password = "asdf" expect(c.auth_decrypted_password).to eql("asdf") c.auth_password = "2t87aot72gho8a37gh4g[awg'waegawe-,v-3o7fya23oya2o3" @@ -65,7 +65,7 @@ describe AccountAuthorizationConfig do let!(:aac){ account.authentication_providers.create!(auth_type: 'facebook') } it "still reloads ok" do - expect { aac.reload }.to_not raise_error + expect { aac.reload }.not_to raise_error end it "works through associations that use the provided module" do @@ -76,22 +76,23 @@ describe AccountAuthorizationConfig do describe "#auth_provider_filter" do it "includes nil for legacy auth types" do - aac = AccountAuthorizationConfig.new(auth_type: "cas") + aac = AuthenticationProvider.new(auth_type: "cas") expect(aac.auth_provider_filter).to eq([nil, aac]) end it "is just the AAC for oauth types" do - aac = AccountAuthorizationConfig.new(auth_type: "facebook") + aac = AuthenticationProvider.new(auth_type: "facebook") expect(aac.auth_provider_filter).to eq(aac) end end describe '#destroy' do - let!(:aac){ account.authentication_providers.create!(auth_type: 'cas') } + let!(:aac) { account.authentication_providers.create!(auth_type: 'cas') } + it "retains the database row" do aac.destroy - found = AccountAuthorizationConfig.find(aac.id) - expect(found).to_not be_nil + found = AuthenticationProvider.find(aac.id) + expect(found).not_to be_nil end it "sets workflow_state upon destroy" do @@ -102,8 +103,8 @@ describe AccountAuthorizationConfig do it "is aliased with #destroy_permanently!" do aac.destroy_permanently! - found = AccountAuthorizationConfig.find(aac.id) - expect(found).to_not be_nil + found = AuthenticationProvider.find(aac.id) + expect(found).not_to be_nil end it "soft-deletes associated pseudonyms" do @@ -117,20 +118,22 @@ describe AccountAuthorizationConfig do end describe ".active" do - let!(:aac){ account.authentication_providers.create!(auth_type: 'cas') } + let!(:aac) { account.authentication_providers.create!(auth_type: 'cas') } + it "finds an aac that isn't deleted" do - expect(AccountAuthorizationConfig.active).to include(aac) + expect(AuthenticationProvider.active).to include(aac) end it "ignores aacs which have been deleted" do aac.destroy - expect(AccountAuthorizationConfig.active).to_not include(aac) + expect(AuthenticationProvider.active).not_to include(aac) end end describe "list-i-ness" do - let!(:aac1){ account.authentication_providers.create!(auth_type: 'facebook') } - let!(:aac2){ account.authentication_providers.create!(auth_type: 'github') } + let!(:aac1) { account.authentication_providers.create!(auth_type: 'facebook') } + let!(:aac2) { account.authentication_providers.create!(auth_type: 'github') } + before do account.authentication_providers.where(auth_type: 'canvas').first.destroy end @@ -176,14 +179,14 @@ describe AccountAuthorizationConfig do it "allows valid provider attributes" do aac = Account.default.authentication_providers.new(auth_type: 'saml', federated_attributes: { 'integration_id' => 'internal_id'}) - allow(AccountAuthorizationConfig::SAML).to receive(:recognized_federated_attributes).and_return(['internal_id']) + allow(AuthenticationProvider::SAML).to receive(:recognized_federated_attributes).and_return(['internal_id']) expect(aac).to be_valid end it "doesn't allow invalid provider attributes" do aac = Account.default.authentication_providers.new(auth_type: 'saml', federated_attributes: { 'integration_id' => 'garbage'}) - allow(AccountAuthorizationConfig::SAML).to receive(:recognized_federated_attributes).and_return(['internal_id']) + allow(AuthenticationProvider::SAML).to receive(:recognized_federated_attributes).and_return(['internal_id']) expect(aac).not_to be_valid end diff --git a/spec/models/course_spec.rb b/spec/models/course_spec.rb index 1db4097d81c..b2ee5790cf6 100644 --- a/spec/models/course_spec.rb +++ b/spec/models/course_spec.rb @@ -4150,10 +4150,10 @@ describe Course do it "should be preferred if delegated authentication is configured" do account = Account.create! - account.settings[:open_registration] = true - account.save! account.authentication_providers.create!(:auth_type => 'cas') account.authentication_providers.first.move_to_bottom + account.settings[:open_registration] = true + account.save! course_factory(account: account) expect(@course.user_list_search_mode_for(nil)).to eq :preferred expect(@course.user_list_search_mode_for(user_factory)).to eq :preferred diff --git a/spec/presenters/account_authorization_configs_presenter_spec.rb b/spec/presenters/authentication_providers_presenter_spec.rb similarity index 84% rename from spec/presenters/account_authorization_configs_presenter_spec.rb rename to spec/presenters/authentication_providers_presenter_spec.rb index 97132563af6..cbf53d7ff7c 100644 --- a/spec/presenters/account_authorization_configs_presenter_spec.rb +++ b/spec/presenters/authentication_providers_presenter_spec.rb @@ -15,9 +15,9 @@ # You should have received a copy of the GNU Affero General Public License along # with this program. If not, see . - require 'spec_helper' +require 'spec_helper' -describe AccountAuthorizationConfigsPresenter do +describe AuthenticationProvidersPresenter do describe "initialization" do it "wraps an account" do account = double() @@ -60,12 +60,12 @@ describe AccountAuthorizationConfigsPresenter do describe "#saml_identifiers" do it "is empty when saml disabled" do - allow(AccountAuthorizationConfig::SAML).to receive(:enabled?).and_return(false) + allow(AuthenticationProvider::SAML).to receive(:enabled?).and_return(false) expect(presenter.saml_identifiers).to be_empty end it "is the list from Onelogin::Saml::NameIdentifiers" do - allow(AccountAuthorizationConfig::SAML).to receive(:enabled?).and_return(true) + allow(AuthenticationProvider::SAML).to receive(:enabled?).and_return(true) expected = Onelogin::Saml::NameIdentifiers::ALL_IDENTIFIERS expect(presenter.saml_identifiers).to eq(expected) end @@ -73,14 +73,14 @@ describe AccountAuthorizationConfigsPresenter do describe "#saml_authn_contexts" do it "is empty when saml disabled" do - allow(AccountAuthorizationConfig::SAML).to receive(:enabled?).and_return(false) + allow(AuthenticationProvider::SAML).to receive(:enabled?).and_return(false) expect(presenter.saml_authn_contexts).to be_empty end context "when saml enabled" do before do - allow(AccountAuthorizationConfig::SAML).to receive(:enabled?).and_return(true) + allow(AuthenticationProvider::SAML).to receive(:enabled?).and_return(true) end it "has each value from Onelogin" do @@ -125,7 +125,7 @@ describe AccountAuthorizationConfigsPresenter do describe "#ldap_config?" do it "is true if theres at least one ldap aac" do - account = stubbed_account([AccountAuthorizationConfig::LDAP.new]) + account = stubbed_account([AuthenticationProvider::LDAP.new]) presenter = described_class.new(account) expect(presenter.ldap_config?).to be(true) end @@ -137,7 +137,7 @@ describe AccountAuthorizationConfigsPresenter do end it "is false for aacs which are not ldap" do - account = stubbed_account( [ double(auth_type: 'saml'), double(auth_type: 'cas') ] ) + account = stubbed_account([double(auth_type: 'saml'), double(auth_type: 'cas')]) presenter = described_class.new(account) expect(presenter.ldap_config?).to be(false) end @@ -145,7 +145,7 @@ describe AccountAuthorizationConfigsPresenter do describe "#sso_options" do it "always has cas and ldap" do - allow(AccountAuthorizationConfig::SAML).to receive(:enabled?).and_return(false) + allow(AuthenticationProvider::SAML).to receive(:enabled?).and_return(false) presenter = described_class.new(stubbed_account) options = presenter.sso_options expect(options).to include({name: 'CAS', value: 'cas'}) @@ -153,7 +153,7 @@ describe AccountAuthorizationConfigsPresenter do end it "includes saml if saml enabled" do - allow(AccountAuthorizationConfig::SAML).to receive(:enabled?).and_return(true) + allow(AuthenticationProvider::SAML).to receive(:enabled?).and_return(true) presenter = described_class.new(stubbed_account) expect(presenter.sso_options).to include({name: 'SAML', value: 'saml'}) end @@ -161,9 +161,9 @@ describe AccountAuthorizationConfigsPresenter do describe "ip_configuration" do def stub_setting(val) - allow(Setting).to receive(:get) - .with('account_authorization_config_ip_addresses', nil) - .and_return(val) + allow(Setting).to receive(:get). + with('account_authorization_config_ip_addresses', nil). + and_return(val) end describe "#ips_configured?" do @@ -205,7 +205,7 @@ describe AccountAuthorizationConfigsPresenter do describe "#login_placeholder" do it "wraps AAC.default_delegated_login_handle_name" do expect(described_class.new(double).login_placeholder).to eq( - AccountAuthorizationConfig.default_delegated_login_handle_name + AuthenticationProvider.default_delegated_login_handle_name ) end end @@ -219,16 +219,16 @@ describe AccountAuthorizationConfigsPresenter do expect(name).to eq("LoginName") end - it "defaults to the provided default on AccountAuthorizationConfig" do + it "defaults to the provided default on AuthenticationProvider" do name = described_class.new(account).login_name - expect(name).to eq(AccountAuthorizationConfig.default_login_handle_name) + expect(name).to eq(AuthenticationProvider.default_login_handle_name) end end describe "#ldap_configs" do it "selects out all ldap configs" do - config = AccountAuthorizationConfig::LDAP.new - config2 = AccountAuthorizationConfig::LDAP.new + config = AuthenticationProvider::LDAP.new + config2 = AuthenticationProvider::LDAP.new account = stubbed_account([double, config, double, config2]) presenter = described_class.new(account) expect(presenter.ldap_configs).to eq([config, config2]) @@ -237,10 +237,10 @@ describe AccountAuthorizationConfigsPresenter do describe "#saml_configs" do it "selects out all saml configs" do - config = AccountAuthorizationConfig::SAML.new - config2 = AccountAuthorizationConfig::SAML.new + config = AuthenticationProvider::SAML.new + config2 = AuthenticationProvider::SAML.new pre_configs = [double, config, double, config2] - allow(pre_configs).to receive(:all).and_return(AccountAuthorizationConfig) + allow(pre_configs).to receive(:all).and_return(AuthenticationProvider) account = stubbed_account(pre_configs) configs = described_class.new(account).saml_configs expect(configs[0]).to eq(config) @@ -250,12 +250,12 @@ describe AccountAuthorizationConfigsPresenter do end describe "#position_options" do - let(:config){ AccountAuthorizationConfig::SAML.new } + let(:config){ AuthenticationProvider::SAML.new } let(:configs){ [config, config, config, config] } let(:account){ stubbed_account(configs) } before do - allow(configs).to receive(:all).and_return(AccountAuthorizationConfig) + allow(configs).to receive(:all).and_return(AuthenticationProvider) end it "generates a list from the saml config size" do @@ -303,10 +303,10 @@ describe AccountAuthorizationConfigsPresenter do describe "#new_auth_types" do it "excludes singletons that have a config" do - allow(AccountAuthorizationConfig::Facebook).to receive(:enabled?).and_return(true) + allow(AuthenticationProvider::Facebook).to receive(:enabled?).and_return(true) Account.default.authentication_providers.create!(auth_type: 'facebook') presenter = described_class.new(Account.default) - expect(presenter.new_auth_types).to_not be_include(AccountAuthorizationConfig::Facebook) + expect(presenter.new_auth_types).not_to be_include(AuthenticationProvider::Facebook) end end end diff --git a/spec/selenium/admin/account_admin_auth_configs_spec.rb b/spec/selenium/admin/account_admin_auth_providers_spec.rb similarity index 96% rename from spec/selenium/admin/account_admin_auth_configs_spec.rb rename to spec/selenium/admin/account_admin_auth_providers_spec.rb index d5772ac555b..a075a634c7e 100644 --- a/spec/selenium/admin/account_admin_auth_configs_spec.rb +++ b/spec/selenium/admin/account_admin_auth_providers_spec.rb @@ -16,11 +16,11 @@ # with this program. If not, see . require_relative '../common' -require_relative '../helpers/accounts_auth_configs_common' +require_relative '../helpers/accounts_auth_providers_common' describe 'account authentication' do include_context 'in-process server selenium tests' - include AccountsAuthConfigsCommon + include AuthenticationProvidersCommon before(:each) do course_with_admin_logged_in @@ -55,7 +55,7 @@ describe 'account authentication' do context 'ldap' do - let!(:ldap_aac) { AccountAuthorizationConfig::LDAP } + let!(:ldap_aac) { AuthenticationProvider::LDAP } it 'should allow creation of config', priority: "1", test_id: 250262 do add_ldap_config @@ -129,7 +129,7 @@ describe 'account authentication' do context 'saml' do - let!(:saml_aac) { AccountAuthorizationConfig::SAML } + let!(:saml_aac) { AuthenticationProvider::SAML } it 'should allow creation of config', priority: "1", test_id: 250266 do add_saml_config @@ -305,7 +305,7 @@ describe 'account authentication' do it 'hides the add attributes button when all are added' do get "/accounts/self/authentication_providers" - AccountAuthorizationConfig::CANVAS_ALLOWED_FEDERATED_ATTRIBUTES.length.times do + AuthenticationProvider::CANVAS_ALLOWED_FEDERATED_ATTRIBUTES.length.times do f(".add_federated_attribute_button").click end expect(f(".add_federated_attribute_button")).not_to be_displayed @@ -345,7 +345,7 @@ describe 'account authentication' do context 'cas' do - let!(:cas_aac) { AccountAuthorizationConfig::CAS } + let!(:cas_aac) { AuthenticationProvider::CAS } it 'should allow creation of config', priority: "1", test_id: 250272 do add_cas_config @@ -381,7 +381,7 @@ describe 'account authentication' do context 'facebook' do - let!(:facebook_aac) { AccountAuthorizationConfig::Facebook } + let!(:facebook_aac) { AuthenticationProvider::Facebook } it 'should allow creation of config', priority: "2", test_id: 250275 do add_facebook_config @@ -418,7 +418,7 @@ describe 'account authentication' do context 'github' do - let!(:github_aac) { AccountAuthorizationConfig::GitHub } + let!(:github_aac) { AuthenticationProvider::GitHub } it 'should allow creation of config', priority: "2", test_id: 250278 do add_github_config @@ -459,7 +459,7 @@ describe 'account authentication' do context 'google' do - let!(:google_aac) { AccountAuthorizationConfig::Google } + let!(:google_aac) { AuthenticationProvider::Google } it 'should allow creation of config', priority: "2", test_id: 250281 do add_google_config @@ -497,7 +497,7 @@ describe 'account authentication' do context 'linkedin' do - let!(:linkedin_aac) { AccountAuthorizationConfig::LinkedIn } + let!(:linkedin_aac) { AuthenticationProvider::LinkedIn } it 'should allow creation of config', priority: "2", test_id: 250284 do add_linkedin_config @@ -535,7 +535,7 @@ describe 'account authentication' do context 'openid connect' do - let!(:openid_aac) { AccountAuthorizationConfig::OpenIDConnect } + let!(:openid_aac) { AuthenticationProvider::OpenIDConnect } it 'should allow creation of config', priority: "2", test_id: 250287 do add_openid_connect_config @@ -582,7 +582,7 @@ describe 'account authentication' do context 'twitter' do - let!(:twitter_aac) { AccountAuthorizationConfig::Twitter } + let!(:twitter_aac) { AuthenticationProvider::Twitter } it 'should allow creation of config', priority: "2", test_id: 250290 do add_twitter_config @@ -620,7 +620,7 @@ describe 'account authentication' do context 'microsoft' do - let!(:microsoft_aac) { AccountAuthorizationConfig::Microsoft } + let!(:microsoft_aac) { AuthenticationProvider::Microsoft } it 'should allow creation of config', priority: "2" do expect(microsoft_aac.active.count).to eq 0 diff --git a/spec/selenium/helpers/accounts_auth_configs_common.rb b/spec/selenium/helpers/accounts_auth_providers_common.rb similarity index 99% rename from spec/selenium/helpers/accounts_auth_configs_common.rb rename to spec/selenium/helpers/accounts_auth_providers_common.rb index ade36bf4528..e0fa2066f78 100644 --- a/spec/selenium/helpers/accounts_auth_configs_common.rb +++ b/spec/selenium/helpers/accounts_auth_providers_common.rb @@ -17,7 +17,7 @@ require_relative "../common" -module AccountsAuthConfigsCommon +module AuthenticationProvidersCommon def add_auth_type(auth_type) click_option("#add-authentication-provider select", auth_type) # public/javascripts/authentication_providers.js waits 100ms to focus diff --git a/spec/views/account_authorization_configs/index.html.erb_spec.rb b/spec/views/authentication_providers/index.html.erb_spec.rb similarity index 85% rename from spec/views/account_authorization_configs/index.html.erb_spec.rb rename to spec/views/authentication_providers/index.html.erb_spec.rb index 79a72ef0794..59427264457 100644 --- a/spec/views/account_authorization_configs/index.html.erb_spec.rb +++ b/spec/views/authentication_providers/index.html.erb_spec.rb @@ -19,7 +19,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require File.expand_path(File.dirname(__FILE__) + '/../views_helper') -describe "account_authorization_configs/index" do +describe "authentication_providers/index" do let(:account){ Account.default } before do @@ -29,17 +29,17 @@ describe "account_authorization_configs/index" do assign(:saml_identifiers, []) assign(:saml_authn_contexts, []) assign(:saml_login_attributes, {}) - @presenter = assign(:presenter, AccountAuthorizationConfigsPresenter.new(account)) + @presenter = assign(:presenter, AuthenticationProvidersPresenter.new(account)) end it "should list the auth ips" do Setting.set('account_authorization_config_ip_addresses', "192.168.0.1,192.168.0.2") account.authentication_providers.scope.delete_all account.authentication_providers = [ - @presenter.new_config(auth_type: 'saml'), - @presenter.new_config(auth_type: 'saml') + @presenter.new_config('saml'), + @presenter.new_config('saml') ] - render 'account_authorization_configs/index' + render 'authentication_providers/index' expect(response.body).to match("192.168.0.1\n192.168.0.2") end @@ -53,7 +53,7 @@ describe "account_authorization_configs/index" do timed_out_aac.last_timeout_failure = 1.minute.ago timed_out_aac.save! expect(@presenter.configs).to include(timed_out_aac) - render 'account_authorization_configs/index' + render 'authentication_providers/index' doc = Nokogiri::HTML(response.body) expect(doc.css('.last_timeout_failure').length).to eq 1 end @@ -63,7 +63,7 @@ describe "account_authorization_configs/index" do 4.times do account.authentication_providers.create!(auth_type: 'ldap') end - render 'account_authorization_configs/index' + render 'authentication_providers/index' doc = Nokogiri::HTML(response.body) expect(doc.css('input[value=ldap]').length).to eq(5) # 4 + 1 hidden for new end @@ -71,7 +71,7 @@ describe "account_authorization_configs/index" do it "doesn't display delete button for the config the current user logged in with" do aac = account.authentication_providers.create!(auth_type: 'ldap') @pseudonym.update_attribute(:authentication_provider, aac) - render 'account_authorization_configs/index' + render 'authentication_providers/index' doc = Nokogiri::HTML(response.body) expect(doc.css("#delete-aac-#{aac.id}")).to be_blank end