From 331fb26bdc265294608c0b6cfeb3bbda880db480 Mon Sep 17 00:00:00 2001 From: Steven Danna Date: Wed, 23 Sep 2015 15:14:19 +0100 Subject: [PATCH 1/2] Use case-insensitive search for user lookup by external_auth_id Almost all of the typical values of ldap['login_attribute'] are case insensitive according to the LDAP schema. However, we previously used a case-sensitive lookup when trying to find an existing user record. This commit changes the default lookup to be case insensitive but provides a user-controllable override for the rare case where users are setting a case-sensitive login_attribute. ChangeLog-Entry: Fix bug where logins via LDAP failed because of case sensitivity. --- .../private-chef/attributes/default.rb | 3 +++ .../templates/default/oc_erchef.config.erb | 1 + .../apps/chef_db/priv/pgsql_statements.config | 19 ++++++++++++++++-- .../apps/chef_objects/src/chef_user.erl | 20 +++++++++++++++---- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/omnibus/files/private-chef-cookbooks/private-chef/attributes/default.rb b/omnibus/files/private-chef-cookbooks/private-chef/attributes/default.rb index 35c8f57451..7901892210 100755 --- a/omnibus/files/private-chef-cookbooks/private-chef/attributes/default.rb +++ b/omnibus/files/private-chef-cookbooks/private-chef/attributes/default.rb @@ -666,6 +666,9 @@ # default['private_chef']['ldap']['base_dn'] = "OU=Employees,OU=Domain users,DC=example,DC=com" # default['private_chef']['ldap']['timeout'] = 60000 # default['private_chef']['ldap']['port'] = 389 +## Nearly every attribute in the standard LDAP schema that users likely set login_attr +## to is case sensitive. +# default['private_chef']['ldap']['case_sensitive_login_attribute'] = false # # default['private_chef']['ldap']['enable_ssl'] = false # default['private_chef']['ldap']['enable_tls'] = false diff --git a/omnibus/files/private-chef-cookbooks/private-chef/templates/default/oc_erchef.config.erb b/omnibus/files/private-chef-cookbooks/private-chef/templates/default/oc_erchef.config.erb index 89607fd053..40cf7f35ac 100755 --- a/omnibus/files/private-chef-cookbooks/private-chef/templates/default/oc_erchef.config.erb +++ b/omnibus/files/private-chef-cookbooks/private-chef/templates/default/oc_erchef.config.erb @@ -84,6 +84,7 @@ {base_dn, "<%= node['private_chef']['ldap']['base_dn'] || "" %>" }, {group_dn, "<%= node['private_chef']['ldap']['group_dn'] || "" %>" }, {login_attribute, "<%= node['private_chef']['ldap']['login_attribute'] || "samaccountname" %>" }, + {case_sensitive_login_attribute, <%= node['private_chef']['ldap']['case_sensitive_login_attribute'] || false %>}, {encryption, <%= @ldap_encryption_type %>} ]}, <% else -%> diff --git a/src/oc_erchef/apps/chef_db/priv/pgsql_statements.config b/src/oc_erchef/apps/chef_db/priv/pgsql_statements.config index 3be1367d8f..825559c7af 100644 --- a/src/oc_erchef/apps/chef_db/priv/pgsql_statements.config +++ b/src/oc_erchef/apps/chef_db/priv/pgsql_statements.config @@ -508,7 +508,7 @@ recovery_authentication_enabled, serialized_object FROM users u LEFT JOIN keys k ON u.id = k.id AND key_name = 'default' - WHERE external_authentication_uid = $1">>}. + WHERE lower(external_authentication_uid) = lower($1)">>}. {find_user_by_external_authentication_uid, <<"SELECT u.id, authz_id, username, email, @@ -516,9 +516,24 @@ u.updated_at, external_authentication_uid, recovery_authentication_enabled, serialized_object FROM users u - WHERE external_authentication_uid = $1">>}. + WHERE lower(external_authentication_uid) = lower($1)">>}. +{find_user_by_sensitive_external_authentication_uid_v0, + <<"SELECT u.id, authz_id, username, email, k.public_key, k.key_version pubkey_version, + hashed_password, salt, hash_type, u.last_updated_by, u.created_at, + u.updated_at, external_authentication_uid, + recovery_authentication_enabled, serialized_object + FROM users u + LEFT JOIN keys k ON u.id = k.id AND key_name = 'default' + WHERE external_authentication_uid = $1">>}. +{find_user_by_sensitive_external_authentication_uid, + <<"SELECT u.id, authz_id, username, email, + hashed_password, salt, hash_type, u.last_updated_by, u.created_at, + u.updated_at, external_authentication_uid, + recovery_authentication_enabled, serialized_object + FROM users u + WHERE external_authentication_uid = $1">>}. {delete_user_by_id, <<"DELETE FROM users WHERE id = $1">>}. diff --git a/src/oc_erchef/apps/chef_objects/src/chef_user.erl b/src/oc_erchef/apps/chef_objects/src/chef_user.erl index 9fa91b5dcf..5a651fd85f 100644 --- a/src/oc_erchef/apps/chef_objects/src/chef_user.erl +++ b/src/oc_erchef/apps/chef_objects/src/chef_user.erl @@ -466,15 +466,27 @@ bulk_get_query(_ObjectRec) -> is_indexed(_ObjectRec) -> false. -fetch(#chef_user{server_api_version = ?API_v0, username = undefined, external_authentication_uid = AuthUid} = Record, CallbackFun) -> - fetch_user(find_user_by_external_authentication_uid_v0, Record, AuthUid, CallbackFun); -fetch(#chef_user{username = undefined, external_authentication_uid = AuthUid} = Record, CallbackFun) -> - fetch_user(find_user_by_external_authentication_uid, Record, AuthUid, CallbackFun); +fetch(#chef_user{server_api_version = ApiVersion, + username = undefined, external_authentication_uid = AuthUid} = Record, CallbackFun) -> + fetch_user(external_auth_id_query(ApiVersion, case_sensitivity()), Record, AuthUid, CallbackFun); fetch(#chef_user{server_api_version = ?API_v0, username = UserName} = Record, CallbackFun) -> fetch_user(find_user_by_username_v0, Record, UserName, CallbackFun); fetch(#chef_user{username = UserName} = Record, CallbackFun) -> fetch_user(find_user_by_username, Record, UserName, CallbackFun). +case_sensitivity() -> + LdapConfig = envy:get(oc_chef_wm, ldap, [], list), + proplists:get_value(case_sensitive_login_attribute, LdapConfig, false). + +external_auth_id_query(?API_v0, true) -> + find_user_by_sensitive_external_authentication_uid_v0; +external_auth_id_query(?API_v0, _NotSensitive) -> + find_user_by_external_authentication_uid_v0; +external_auth_id_query(_Not0, true) -> + find_user_by_sensitive_external_authentication_uid; +external_auth_id_query(_Not0, _NotSensitive) -> + find_user_by_external_authentication_uid. + fetch_user(Query, Record, KeyValue, CallbackFun) -> CallbackFun({Query, [KeyValue], {first_as_record, [chef_user, record_fields(Record)]}}). From 611634446d92a69071b668d1bd7554c99e893b0f Mon Sep 17 00:00:00 2001 From: Steven Danna Date: Wed, 23 Sep 2015 15:50:49 +0100 Subject: [PATCH 2/2] Rename case_sensitivity to ldap_case_sensitivity for clarity --- src/oc_erchef/apps/chef_objects/src/chef_user.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/oc_erchef/apps/chef_objects/src/chef_user.erl b/src/oc_erchef/apps/chef_objects/src/chef_user.erl index 5a651fd85f..60351cde04 100644 --- a/src/oc_erchef/apps/chef_objects/src/chef_user.erl +++ b/src/oc_erchef/apps/chef_objects/src/chef_user.erl @@ -468,13 +468,13 @@ is_indexed(_ObjectRec) -> fetch(#chef_user{server_api_version = ApiVersion, username = undefined, external_authentication_uid = AuthUid} = Record, CallbackFun) -> - fetch_user(external_auth_id_query(ApiVersion, case_sensitivity()), Record, AuthUid, CallbackFun); + fetch_user(external_auth_id_query(ApiVersion, ldap_case_sensitivity()), Record, AuthUid, CallbackFun); fetch(#chef_user{server_api_version = ?API_v0, username = UserName} = Record, CallbackFun) -> fetch_user(find_user_by_username_v0, Record, UserName, CallbackFun); fetch(#chef_user{username = UserName} = Record, CallbackFun) -> fetch_user(find_user_by_username, Record, UserName, CallbackFun). -case_sensitivity() -> +ldap_case_sensitivity() -> LdapConfig = envy:get(oc_chef_wm, ldap, [], list), proplists:get_value(case_sensitive_login_attribute, LdapConfig, false).