rename AccountAuthorizationConfig* to AuthenticationProvider*

I couldn't take it anymore. it was driving me crazy

Change-Id: Ib40addff56e98a6e0a6d80f246c208e0ce0cb762
Reviewed-on: https://gerrit.instructure.com/148026
Tested-by: Jenkins
Reviewed-by: James Williams  <jamesw@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
QA-Review: Cody Cutrer <cody@instructure.com>
This commit is contained in:
Cody Cutrer 2018-04-24 15:49:30 -06:00
parent af039d8bb8
commit 41794a9383
104 changed files with 806 additions and 724 deletions

View File

@ -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
@ -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
@ -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

View File

@ -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),
)

View File

@ -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 = {}

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -16,331 +16,5 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
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: <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

View File

@ -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 <http://www.gnu.org/licenses/>.
#
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: <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'

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class AccountAuthorizationConfig::Canvas < AccountAuthorizationConfig
class AuthenticationProvider::Canvas < AuthenticationProvider
def self.sti_name
'canvas'
end

View File

@ -18,7 +18,7 @@
require 'casclient'
class AccountAuthorizationConfig::CAS < AccountAuthorizationConfig::Delegated
class AuthenticationProvider::CAS < AuthenticationProvider::Delegated
def self.sti_name
'cas'.freeze

View File

@ -16,8 +16,8 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
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

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
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

View File

@ -16,8 +16,8 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
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

View File

@ -16,8 +16,8 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
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

View File

@ -16,8 +16,8 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
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

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
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

View File

@ -16,8 +16,8 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
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

View File

@ -16,8 +16,8 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
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

View File

@ -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

View File

@ -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

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class AccountAuthorizationConfig::OpenIDConnect < AccountAuthorizationConfig::Oauth2
class AuthenticationProvider::OpenIDConnect < AuthenticationProvider::Oauth2
def self.sti_name
self == OpenIDConnect ? 'openid_connect'.freeze : super
end

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
module AccountAuthorizationConfig::PluginSettings
module AuthenticationProvider::PluginSettings
module ClassMethods
def singleton?
true

View File

@ -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,15 +82,16 @@ 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?
next unless metadata_uri == federation::URN
if idp_entity_id.blank?
errors.add(:idp_entity_id, :present)
return
end
@ -108,7 +110,6 @@ class AccountAuthorizationConfig::SAML < AccountAuthorizationConfig::Delegated
end
return
end
end
begin
populate_from_metadata_url(metadata_uri)
@ -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
@ -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,

View File

@ -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'

View File

@ -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

View File

@ -18,11 +18,11 @@
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.
federations = AuthenticationProvider::SAML::Federation.descendants.map { |federation| federation::URN }
providers ||= AuthenticationProvider::SAML.active.
where.not(metadata_uri: [nil, ""] + federations).
shard(shard_scope)

View File

@ -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

View File

@ -16,8 +16,8 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
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

View File

@ -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,11 +422,11 @@ 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

View File

@ -15,7 +15,7 @@
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
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)

View File

@ -144,7 +144,7 @@
</tr>
<% 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
%>
<tr>

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
%>
<% unless AccountAuthorizationConfig::Clever.globally_configured? %>
<% unless AuthenticationProvider::Clever.globally_configured? %>
<p><%= 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.

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
%>
<% unless AccountAuthorizationConfig::Facebook.globally_configured? %>
<% unless AuthenticationProvider::Facebook.globally_configured? %>
<p><%= 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.

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
%>
<% unless AccountAuthorizationConfig::GitHub.globally_configured? %>
<% unless AuthenticationProvider::GitHub.globally_configured? %>
<p><%= 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.

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
%>
<% unless AccountAuthorizationConfig::Google.globally_configured? %>
<% unless AuthenticationProvider::Google.globally_configured? %>
<p><%= 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.

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
%>
<% unless AccountAuthorizationConfig::LinkedIn.globally_configured? %>
<% unless AuthenticationProvider::LinkedIn.globally_configured? %>
<p><%= 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

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
%>
<% unless AccountAuthorizationConfig::Microsoft.globally_configured? %>
<% unless AuthenticationProvider::Microsoft.globally_configured? %>
<p><%= 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.

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
%>
<% unless AccountAuthorizationConfig::Twitter.globally_configured? %>
<% unless AuthenticationProvider::Twitter.globally_configured? %>
<p><%= 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.

View File

@ -82,7 +82,6 @@
<h2><%= t("Current Provider") %></h2>
<% if @presenter.configs.empty? %>
<div id="no_auth">
<%= 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 %>

View File

@ -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)

View File

@ -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

View File

@ -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'

View File

@ -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!

View File

@ -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

View File

@ -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
UPDATE #{connection.quote_table_name('account_authorization_configs')} aac
SET position =
CASE WHEN (SELECT count(*) FROM #{AccountAuthorizationConfig.quoted_table_name} WHERE account_id = aac.account_id) > 1
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
else
update <<-SQL
UPDATE #{AccountAuthorizationConfig.quoted_table_name}
SET position = account_authorization_configs.id;
SQL
end
end
def self.down

View File

@ -19,9 +19,11 @@ class DropLdapAuthSettingsFromAacs < ActiveRecord::Migration[4.2]
tag :postdeploy
def up
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
add_column :account_authorization_configs, :login_handle_name, :string

View File

@ -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

View File

@ -19,8 +19,10 @@ class DropUnknownUserUrlFromAccountAuthorizationConfigs < ActiveRecord::Migratio
tag :postdeploy
def up
AuthenticationProvider.maybe_recreate_view do
remove_column :account_authorization_configs, :unknown_user_url
end
end
def down
add_column :account_authorization_configs, :unknown_user_url, :string

View File

@ -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

View File

@ -19,8 +19,10 @@ class ChangeAuthFilterToText < ActiveRecord::Migration[4.2]
tag :postdeploy
def self.up
AuthenticationProvider.maybe_recreate_view do
change_column :account_authorization_configs, :auth_filter, :text
end
end
def self.down
change_column :account_authorization_configs, :auth_filter, :string

View File

@ -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

View File

@ -29,6 +29,7 @@ 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
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
@ -44,6 +45,7 @@ class AddBackDefaultStringLimitsP1 < ActiveRecord::Migration[4.2]
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

View File

@ -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

View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>.
#
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

View File

@ -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 <http://www.gnu.org/licenses/>.
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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -16,7 +16,7 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
module Api::V1::AccountAuthorizationConfig
module Api::V1::AuthenticationProvider
include Api::V1::Json
def aacs_json(aacs)

View File

@ -213,15 +213,18 @@ module Canvas::Security
Account => {
:encrypted_column => :turnitin_crypted_secret,
:salt_column => :turnitin_salt,
:key => 'instructure_turnitin_secret_shared' },
AccountAuthorizationConfig => {
:key => 'instructure_turnitin_secret_shared'
},
AuthenticationProvider => {
:encrypted_column => :auth_crypted_password,
:salt_column => :auth_password_salt,
:key => 'instructure_auth' },
:key => 'instructure_auth'
},
UserService => {
:encrypted_column => :crypted_password,
:salt_column => :password_salt,
:key => 'instructure_user_service' },
:key => 'instructure_user_service'
},
User => {
:encrypted_column => :otp_secret_key_enc,
:salt_column => :otp_secret_key_salt,

View File

@ -16,15 +16,24 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
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!

View File

@ -16,7 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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'

View File

@ -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=)

View File

@ -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

View File

@ -18,7 +18,7 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe AccountAuthorizationConfigsController do
describe AuthenticationProvidersController do
let!(:account) { Account.create! }

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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 <http://www.gnu.org/licenses/>.
#
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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',

View File

@ -18,12 +18,12 @@
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') }
@ -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

View File

@ -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'

View File

@ -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') }
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
@ -118,19 +119,21 @@ describe AccountAuthorizationConfig do
describe ".active" do
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') }
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

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More