Hello community, here is the log from the commit of package rubygem-devise_ldap_authenticatable for openSUSE:Factory checked in at 2018-03-08 10:56:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-devise_ldap_authenticatable (Old) and /work/SRC/openSUSE:Factory/.rubygem-devise_ldap_authenticatable.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-devise_ldap_authenticatable" Thu Mar 8 10:56:55 2018 rev:2 rq:577156 version:0.8.6 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-devise_ldap_authenticatable/rubygem-devise_ldap_authenticatable.changes 2018-01-10 23:30:45.352446313 +0100 +++ /work/SRC/openSUSE:Factory/.rubygem-devise_ldap_authenticatable.new/rubygem-devise_ldap_authenticatable.changes 2018-03-08 10:56:57.654500505 +0100 @@ -1,0 +2,6 @@ +Wed Feb 14 05:28:56 UTC 2018 - factory-a...@kulow.org + +- updated to version 0.8.6 + see installed CHANGELOG.md + +------------------------------------------------------------------- Old: ---- devise_ldap_authenticatable-0.8.5.gem New: ---- devise_ldap_authenticatable-0.8.6.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-devise_ldap_authenticatable.spec ++++++ --- /var/tmp/diff_new_pack.FgR2k7/_old 2018-03-08 10:56:58.690463213 +0100 +++ /var/tmp/diff_new_pack.FgR2k7/_new 2018-03-08 10:56:58.694463069 +0100 @@ -1,7 +1,7 @@ # # spec file for package rubygem-devise_ldap_authenticatable # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -24,16 +24,16 @@ # Name: rubygem-devise_ldap_authenticatable -Version: 0.8.5 +Version: 0.8.6 Release: 0 %define mod_name devise_ldap_authenticatable %define mod_full_name %{mod_name}-%{version} BuildRoot: %{_tmppath}/%{name}-%{version}-build -BuildRequires: ruby-macros >= 5 -BuildRequires: %{ruby} BuildRequires: %{rubygem gem2rpm} +BuildRequires: %{ruby} +BuildRequires: ruby-macros >= 5 Url: https://github.com/cschiewek/devise_ldap_authenticatable -Source: http://rubygems.org/gems/%{mod_full_name}.gem +Source: https://rubygems.org/gems/%{mod_full_name}.gem Source1: gem2rpm.yml Summary: Devise extension to allow authentication via LDAP License: MIT ++++++ devise_ldap_authenticatable-0.8.5.gem -> devise_ldap_authenticatable-0.8.6.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 2015-06-19 18:22:40.000000000 +0200 +++ new/.gitignore 2018-02-13 19:06:27.000000000 +0100 @@ -7,4 +7,5 @@ test/ldap/openldap-data/run/slapd.* test/rails_app/tmp pkg/* -*.gem \ No newline at end of file +*.gem +.vscode diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/README.md new/README.md --- old/README.md 2015-06-19 18:22:40.000000000 +0200 +++ new/README.md 2018-02-13 19:06:27.000000000 +0100 @@ -1,10 +1,5 @@ Devise LDAP Authenticatable =========================== - -Why this fork? --------------- -This fork changes a few lines to allow the admin binding to be set to the user trying to log in. - [![Gem Version](https://badge.fury.io/rb/devise_ldap_authenticatable.png)](http://badge.fury.io/rb/devise_ldap_authenticatable) [![Code Climate](https://codeclimate.com/github/cschiewek/devise_ldap_authenticatable.png)](https://codeclimate.com/github/cschiewek/devise_ldap_authenticatable) [![Dependency Status](https://gemnasium.com/cschiewek/devise_ldap_authenticatable.png)](https://gemnasium.com/cschiewek/devise_ldap_authenticatable) @@ -15,7 +10,7 @@ Devise LDAP Authenticatable works in replacement of Database Authenticatable. This devise plugin has not been tested with DatabaseAuthenticatable enabled at the same time. This is meant as a drop in replacement for DatabaseAuthenticatable allowing for a semi single sign on approach. -For a screencast with an example application, please visit: [http://random-rails.blogspot.com/2010/07/ldap-authentication-with-devise.html](http://random-rails.blogspot.com/2010/07/ldap-authentication-with-devise.html) +For a screencast with an example application, please visit: [http://corrupt.net/2010/07/05/LDAP-Authentication-With-Devise/](http://corrupt.net/2010/07/05/LDAP-Authentication-With-Devise/) Prerequisites ------------- @@ -24,6 +19,8 @@ Note: Rails 3.x / Devise 2.x has been moved to the 0.7 branch. All 0.7.x gems will support Rails 3, where as 0.8.x will support Rails 4. +If you are transitioning from having Devise manage your users' passwords in the database to using LDAP auth, you may have to update your `users` table to make `encrypted_password` nullable, or else the LDAP user insert will fail. + Usage ----- In the Gemfile for your application: @@ -83,7 +80,9 @@ * `ldap_check_group_membership` _(default: false)_ * When set to true, the user trying to login will be checked to make sure they are in all of groups specified in the ldap.yml file. * `ldap_check_attributes` _(default: false)_ - * When set to true, the user trying to login will be checked to make sure they have all of the attributes in the ldap.yml file. + * When set to true, the user trying to login will be checked to make sure their attributes match those specified in the ldap.yml file. +* `ldap_check_attributes_presence` _(default: false)_ + * When set to true, the user trying to login will be checked against all `require_attribute_presence` attributes in the ldap.yml file, either present _(attr: true)_,or not present _(attr: false)_. * `ldap_use_admin_to_bind` _(default: false)_ * When set to true, the admin user will be used to bind to the LDAP server during authentication. * `ldap_check_group_membership_without_admin` _(default: false)_ @@ -116,9 +115,9 @@ On OS X, this is available out of the box. -On Ubuntu, you can install OpenLDAP with `sudo apt-get install slapd ldap-utils`. If slapd runs under AppArmor, add an exception like this to `/etc/apparmor.d/local/usr.sbin.slapd` to let slapd read our configs. +On Ubuntu, you can install OpenLDAP with `sudo apt-get install slapd ldap-utils`. If slapd runs under AppArmor, add an exception like this to `/etc/apparmor.d/local/usr.sbin.slapd` to let slapd read our configs (reload using `sudo service apparmor reload` afterwards). - /path/to/devise_ldap_authenticatable/spec/ldap/** rw,$ + /path/to/devise_ldap_authenticatable/spec/ldap/** rw, To start hacking on `devise_ldap_authentication`, clone the github repository, start the test LDAP server, and run the rake test task: @@ -129,7 +128,7 @@ # in a separate console or backgrounded ./spec/ldap/run-server - bundle exec rake db:migrate # first time only + RAILS_ENV=test bundle exec rake db:migrate # first time only bundle exec rake spec References Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devise_ldap_authenticatable.gemspec new/devise_ldap_authenticatable.gemspec --- old/devise_ldap_authenticatable.gemspec 2015-06-19 18:22:40.000000000 +0200 +++ new/devise_ldap_authenticatable.gemspec 2018-02-13 19:06:27.000000000 +0100 @@ -18,16 +18,16 @@ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] - s.add_dependency('devise', '>= 3.4.1') - s.add_dependency('net-ldap', '>= 0.6.0', '<= 0.11') + s.add_dependency 'devise', '>= 3.4.1' + s.add_dependency 'net-ldap', '>= 0.16.0' - s.add_development_dependency('rake', '>= 0.9') - s.add_development_dependency('rdoc', '>= 3') - s.add_development_dependency('rails', '>= 4.0') - s.add_development_dependency('sqlite3') - s.add_development_dependency('factory_girl_rails', '~> 1.0') - s.add_development_dependency('factory_girl', '~> 2.0') - s.add_development_dependency('rspec-rails') + s.add_development_dependency 'rake', '>= 0.9' + s.add_development_dependency 'rdoc', '>= 3' + s.add_development_dependency 'rails', '>= 4.0' + s.add_development_dependency 'sqlite3' + s.add_development_dependency 'factory_girl_rails', '~> 1.0' + s.add_development_dependency 'factory_girl', '~> 2.0' + s.add_development_dependency 'rspec-rails' %w{database_cleaner capybara launchy}.each do |dep| s.add_development_dependency(dep) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/devise_ldap_authenticatable/ldap/adapter.rb new/lib/devise_ldap_authenticatable/ldap/adapter.rb --- old/lib/devise_ldap_authenticatable/ldap/adapter.rb 2015-06-19 18:22:40.000000000 +0200 +++ new/lib/devise_ldap_authenticatable/ldap/adapter.rb 2018-02-13 19:06:27.000000000 +0100 @@ -15,6 +15,16 @@ resource.authorized? end + def self.expired_valid_credentials?(login, password_plaintext) + options = {:login => login, + :password => password_plaintext, + :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder, + :admin => ::Devise.ldap_use_admin_to_bind} + + resource = Devise::LDAP::Connection.new(options) + resource.expired_valid_credentials? + end + def self.update_password(login, new_password) options = {:login => login, :new_password => new_password, @@ -34,7 +44,7 @@ :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder, :admin => ::Devise.ldap_use_admin_to_bind} - resource = Devise::LDAP::Connection.new(options) + Devise::LDAP::Connection.new(options) end def self.valid_login?(login) @@ -54,18 +64,18 @@ end def self.set_ldap_param(login, param, new_value, password = nil) - options = { :login => login, - :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder, - :password => password } + options = {:login => login, + :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder, + :password => password } resource = Devise::LDAP::Connection.new(options) resource.set_param(param, new_value) end def self.delete_ldap_param(login, param, password = nil) - options = { :login => login, - :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder, - :password => password } + options = {:login => login, + :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder, + :password => password } resource = Devise::LDAP::Connection.new(options) resource.delete_param(param) @@ -79,9 +89,6 @@ def self.get_ldap_entry(login) self.ldap_connect(login).search_for_login end - end - end - end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/devise_ldap_authenticatable/ldap/connection.rb new/lib/devise_ldap_authenticatable/ldap/connection.rb --- old/lib/devise_ldap_authenticatable/ldap/connection.rb 2015-06-19 18:22:40.000000000 +0200 +++ new/lib/devise_ldap_authenticatable/ldap/connection.rb 2018-02-13 19:06:27.000000000 +0100 @@ -24,11 +24,13 @@ @group_base = ldap_config["group_base"] @check_group_membership = ldap_config.has_key?("check_group_membership") ? ldap_config["check_group_membership"] : ::Devise.ldap_check_group_membership + @check_group_membership_without_admin = ldap_config.has_key?("check_group_membership_without_admin") ? ldap_config["check_group_membership_without_admin"] : ::Devise.ldap_check_group_membership_without_admin @required_groups = ldap_config["required_groups"] + @group_membership_attribute = ldap_config.has_key?("group_membership_attribute") ? ldap_config["group_membership_attribute"] : "uniqueMember" @required_attributes = ldap_config["require_attribute"] + @required_attributes_presence = ldap_config["require_attribute_presence"] @ldap.auth ldap_config["admin_user"], ldap_config["admin_password"] if params[:admin] - @ldap.auth params[:login], params[:password] if ldap_config["admin_as_user"] @login = params[:login] @password = params[:password] @@ -83,10 +85,25 @@ authenticate! end + def last_message_bad_credentials? + @ldap.get_operation_result.error_message.to_s.include? 'AcceptSecurityContext error, data 52e' + end + + def last_message_expired_credentials? + @ldap.get_operation_result.error_message.to_s.include? 'AcceptSecurityContext error, data 773' + end + def authorized? DeviseLdapAuthenticatable::Logger.send("Authorizing user #{dn}") if !authenticated? - DeviseLdapAuthenticatable::Logger.send("Not authorized because not authenticated.") + if last_message_bad_credentials? + DeviseLdapAuthenticatable::Logger.send("Not authorized because of invalid credentials.") + elsif last_message_expired_credentials? + DeviseLdapAuthenticatable::Logger.send("Not authorized because of expired credentials.") + else + DeviseLdapAuthenticatable::Logger.send("Not authorized because not authenticated.") + end + return false elsif !in_required_groups? DeviseLdapAuthenticatable::Logger.send("Not authorized because not in required groups.") @@ -94,17 +111,26 @@ elsif !has_required_attribute? DeviseLdapAuthenticatable::Logger.send("Not authorized because does not have required attribute.") return false + elsif !has_required_attribute_presence? + DeviseLdapAuthenticatable::Logger.send("Not authorized because does not have required attribute present.") + return false else return true end end + def expired_valid_credentials? + DeviseLdapAuthenticatable::Logger.send("Authorizing user #{dn}") + + !authenticated? && last_message_expired_credentials? + end + def change_password! - update_ldap(:userpassword => Net::LDAP::Password.generate(:sha, @new_password)) + update_ldap(:userPassword => ::Devise.ldap_auth_password_builder.call(@new_password)) end def in_required_groups? - return true unless @check_group_membership + return true unless @check_group_membership || @check_group_membership_without_admin ## FIXME set errors here, the ldap.yml isn't set properly. return false if @required_groups.nil? @@ -122,23 +148,29 @@ def in_group?(group_name, group_attribute = LDAP::DEFAULT_GROUP_UNIQUE_MEMBER_LIST_KEY) in_group = false - admin_ldap = Connection.admin + if @check_group_membership_without_admin + group_checking_ldap = @ldap + else + group_checking_ldap = Connection.admin + end unless ::Devise.ldap_ad_group_check - admin_ldap.search(:base => group_name, :scope => Net::LDAP::SearchScope_BaseObject) do |entry| + group_checking_ldap.search(:base => group_name, :scope => Net::LDAP::SearchScope_BaseObject) do |entry| if entry[group_attribute].include? dn in_group = true + DeviseLdapAuthenticatable::Logger.send("User #{dn} IS included in group: #{group_name}") end end else # AD optimization - extension will recursively check sub-groups with one query # "(memberof:1.2.840.113556.1.4.1941:=group_name)" - search_result = admin_ldap.search(:base => dn, + search_result = group_checking_ldap.search(:base => dn, :filter => Net::LDAP::Filter.ex("memberof:1.2.840.113556.1.4.1941", group_name), :scope => Net::LDAP::SearchScope_BaseObject) # Will return the user entry if belongs to group otherwise nothing if search_result.length == 1 && search_result[0].dn.eql?(dn) in_group = true + DeviseLdapAuthenticatable::Logger.send("User #{dn} IS included in group: #{group_name}") end end @@ -153,11 +185,11 @@ return true unless ::Devise.ldap_check_attributes admin_ldap = Connection.admin - user = find_ldap_user(admin_ldap) @required_attributes.each do |key,val| - unless user[key].include? val + matching_attributes = user[key] & Array(val) + unless (matching_attributes).any? DeviseLdapAuthenticatable::Logger.send("User #{dn} did not match attribute #{key}:#{val}") return false end @@ -166,11 +198,28 @@ return true end + def has_required_attribute_presence? + return true unless ::Devise.ldap_check_attributes_presence + + user = search_for_login + + @required_attributes_presence.each do |key,val| + if val && !user.attribute_names.include?(key.to_sym) + DeviseLdapAuthenticatable::Logger.send("User #{dn} doesn't include attribute #{key}") + return false + elsif !val && user.attribute_names.include?(key.to_sym) + DeviseLdapAuthenticatable::Logger.send("User #{dn} includes attribute #{key}") + return false + end + end + + return true + end + def user_groups admin_ldap = Connection.admin - DeviseLdapAuthenticatable::Logger.send("Getting groups for #{dn}") - filter = Net::LDAP::Filter.eq("uniqueMember", dn) + filter = Net::LDAP::Filter.eq(@group_membership_attribute, dn) admin_ldap.search(:filter => filter, :base => @group_base).collect(&:dn) end @@ -188,6 +237,10 @@ ldap_entry = nil match_count = 0 @ldap.search(:filter => filter) {|entry| ldap_entry = entry; match_count+=1} + op_result= @ldap.get_operation_result + if op_result.code!=0 then + DeviseLdapAuthenticatable::Logger.send("LDAP Error #{op_result.code}: #{op_result.message}") + end DeviseLdapAuthenticatable::Logger.send("LDAP search yielded #{match_count} matches") ldap_entry end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/devise_ldap_authenticatable/model.rb new/lib/devise_ldap_authenticatable/model.rb --- old/lib/devise_ldap_authenticatable/model.rb 2015-06-19 18:22:40.000000000 +0200 +++ new/lib/devise_ldap_authenticatable/model.rb 2018-02-13 19:06:27.000000000 +0100 @@ -53,7 +53,7 @@ end def ldap_groups - Devise::LDAP::Adapter.get_groups(login_with) + @ldap_groups ||= Devise::LDAP::Adapter.get_groups(login_with) end def in_ldap_group?(group_name, group_attribute = LDAP::DEFAULT_GROUP_UNIQUE_MEMBER_LIST_KEY) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/devise_ldap_authenticatable/strategy.rb new/lib/devise_ldap_authenticatable/strategy.rb --- old/lib/devise_ldap_authenticatable/strategy.rb 2015-06-19 18:22:40.000000000 +0200 +++ new/lib/devise_ldap_authenticatable/strategy.rb 2018-02-13 19:06:27.000000000 +0100 @@ -10,7 +10,7 @@ # indicating whether the resource is not found in the database or the credentials # are invalid. def authenticate! - resource = mapping.to.find_for_ldap_authentication(authentication_hash.merge(password: password)) + resource = mapping.to.find_for_ldap_authentication(authentication_hash.merge(:password => password)) return fail(:invalid) unless resource diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/devise_ldap_authenticatable/version.rb new/lib/devise_ldap_authenticatable/version.rb --- old/lib/devise_ldap_authenticatable/version.rb 2015-06-19 18:22:40.000000000 +0200 +++ new/lib/devise_ldap_authenticatable/version.rb 2018-02-13 19:06:27.000000000 +0100 @@ -1,3 +1,3 @@ module DeviseLdapAuthenticatable - VERSION = "0.8.5".freeze + VERSION = "0.8.6".freeze end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/devise_ldap_authenticatable.rb new/lib/devise_ldap_authenticatable.rb --- old/lib/devise_ldap_authenticatable.rb 2015-06-19 18:22:40.000000000 +0200 +++ new/lib/devise_ldap_authenticatable.rb 2018-02-13 19:06:27.000000000 +0100 @@ -1,5 +1,6 @@ # encoding: utf-8 require 'devise' +require 'net/ldap' require 'devise_ldap_authenticatable/exception' require 'devise_ldap_authenticatable/logger' @@ -11,31 +12,40 @@ # Allow logging mattr_accessor :ldap_logger @@ldap_logger = true - + # Add valid users to database mattr_accessor :ldap_create_user @@ldap_create_user = false - + # A path to YAML config file or a Proc that returns a # configuration hash mattr_accessor :ldap_config # @@ldap_config = "#{Rails.root}/config/ldap.yml" - + mattr_accessor :ldap_update_password @@ldap_update_password = true - + mattr_accessor :ldap_check_group_membership @@ldap_check_group_membership = false - + + mattr_accessor :ldap_check_group_membership_without_admin + @@ldap_check_group_membership_without_admin = false + mattr_accessor :ldap_check_attributes @@ldap_check_role_attribute = false - + + mattr_accessor :ldap_check_attributes_presence + @@ldap_check_attributes_presence = false + mattr_accessor :ldap_use_admin_to_bind @@ldap_use_admin_to_bind = false - + mattr_accessor :ldap_auth_username_builder @@ldap_auth_username_builder = Proc.new() {|attribute, login, ldap| "#{attribute}=#{login},#{ldap.base}" } + mattr_accessor :ldap_auth_password_builder + @@ldap_auth_password_builder = Proc.new() {|new_password| Net::LDAP::Password.generate(:sha, new_password) } + mattr_accessor :ldap_ad_group_check @@ldap_ad_group_check = false end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/generators/devise_ldap_authenticatable/install_generator.rb new/lib/generators/devise_ldap_authenticatable/install_generator.rb --- old/lib/generators/devise_ldap_authenticatable/install_generator.rb 2015-06-19 18:22:40.000000000 +0200 +++ new/lib/generators/devise_ldap_authenticatable/install_generator.rb 2018-02-13 19:06:27.000000000 +0100 @@ -13,7 +13,7 @@ end def create_default_devise_settings - inject_into_file "config/initializers/devise.rb", default_devise_settings, :after => "Devise.setup do |config|\n" + inject_into_file "config/initializers/devise.rb", default_devise_settings, :after => "Devise.setup do |config|\n" end def update_user_model @@ -28,7 +28,7 @@ def default_devise_settings settings = <<-eof - # ==> LDAP Configuration + # ==> LDAP Configuration # config.ldap_logger = true # config.ldap_create_user = false # config.ldap_update_password = true @@ -36,12 +36,13 @@ # config.ldap_check_group_membership = false # config.ldap_check_group_membership_without_admin = false # config.ldap_check_attributes = false + # config.ldap_check_attributes_presence = false # config.ldap_use_admin_to_bind = false # config.ldap_ad_group_check = false eof - if options.advanced? - settings << <<-eof + if options.advanced? + settings << <<-eof # ==> Advanced LDAP Configuration # config.ldap_auth_username_builder = Proc.new() {|attribute, login, ldap| "\#{attribute}=\#{login},\#{ldap.base}" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/generators/devise_ldap_authenticatable/templates/ldap.yml new/lib/generators/devise_ldap_authenticatable/templates/ldap.yml --- old/lib/generators/devise_ldap_authenticatable/templates/ldap.yml 2015-06-19 18:22:40.000000000 +0200 +++ new/lib/generators/devise_ldap_authenticatable/templates/ldap.yml 2018-02-13 19:06:27.000000000 +0100 @@ -1,7 +1,7 @@ ## Authorizations # Uncomment out the merging for each environment that you'd like to include. # You can also just copy and paste the tree (do not include the "authorizations") to each -# environment if you need something different per enviornment. +# environment if you need something different per environment. authorizations: &AUTHORIZATIONS allow_unauthenticated_bind: false group_base: ou=groups,dc=test,dc=com @@ -18,6 +18,12 @@ require_attribute: objectClass: inetOrgPerson authorizationRole: postsAdmin + ## Requires config.ldap_check_attributes_presence in devise.rb to be true + ## Can have multiple attributes set to true or false to check presence, all must match all to be authorized + require_attribute_presence: + mail: true + telephoneNumber: true + serviceAccount: false ## Environment diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2015-06-19 18:22:40.000000000 +0200 +++ new/metadata 2018-02-13 19:06:27.000000000 +0100 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: devise_ldap_authenticatable version: !ruby/object:Gem::Version - version: 0.8.5 + version: 0.8.6 platform: ruby authors: - Curtis Schiewek @@ -10,7 +10,7 @@ autorequire: bindir: bin cert_chain: [] -date: 2015-06-19 00:00:00.000000000 Z +date: 2018-02-13 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: devise @@ -32,20 +32,14 @@ requirements: - - ">=" - !ruby/object:Gem::Version - version: 0.6.0 - - - "<=" - - !ruby/object:Gem::Version - version: '0.11' + version: 0.16.0 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version - version: 0.6.0 - - - "<=" - - !ruby/object:Gem::Version - version: '0.11' + version: 0.16.0 - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement @@ -277,6 +271,7 @@ - spec/rails_app/script/rails - spec/spec_helper.rb - spec/support/factories.rb +- spec/unit/adapter_spec.rb - spec/unit/connection_spec.rb - spec/unit/user_spec.rb homepage: https://github.com/cschiewek/devise_ldap_authenticatable @@ -299,7 +294,7 @@ version: '0' requirements: [] rubyforge_project: -rubygems_version: 2.4.6 +rubygems_version: 2.6.11 signing_key: specification_version: 4 summary: Devise extension to allow authentication via LDAP @@ -372,5 +367,6 @@ - spec/rails_app/script/rails - spec/spec_helper.rb - spec/support/factories.rb +- spec/unit/adapter_spec.rb - spec/unit/connection_spec.rb - spec/unit/user_spec.rb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/rails_app/config/ldap.yml new/spec/rails_app/config/ldap.yml --- old/spec/rails_app/config/ldap.yml 2015-06-19 18:22:40.000000000 +0200 +++ new/spec/rails_app/config/ldap.yml 2018-02-13 19:06:27.000000000 +0100 @@ -7,7 +7,9 @@ require_attribute: objectClass: inetOrgPerson authorizationRole: blogAdmin - + require_attribute_presence: + mail: true + test: &TEST host: localhost port: 3389 @@ -17,6 +19,6 @@ admin_password: secret ssl: false <<: *AUTHORIZATIONS - + development: <<: *TEST diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/rails_app/config/ldap_with_erb.yml new/spec/rails_app/config/ldap_with_erb.yml --- old/spec/rails_app/config/ldap_with_erb.yml 2015-06-19 18:22:40.000000000 +0200 +++ new/spec/rails_app/config/ldap_with_erb.yml 2018-02-13 19:06:27.000000000 +0100 @@ -6,9 +6,11 @@ required_groups: - cn=admins,<%= "ou=groups,#{@base}" %> require_attribute: - objectClass: inetOrgPerson + objectClass: + - inetOrgPerson + - organizationalPerson authorizationRole: blogAdmin - + test: &TEST host: <%= "localhost" %> port: 3389 @@ -18,6 +20,6 @@ admin_password: secret ssl: false <<: *AUTHORIZATIONS - + development: <<: *TEST diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/spec_helper.rb new/spec/spec_helper.rb --- old/spec/spec_helper.rb 2015-06-19 18:22:40.000000000 +0200 +++ new/spec/spec_helper.rb 2018-02-13 19:06:27.000000000 +0100 @@ -2,7 +2,6 @@ require File.expand_path("rails_app/config/environment.rb", File.dirname(__FILE__)) require 'rspec/rails' -require 'rspec/autorun' require 'factory_girl' # not sure why this is not already required # Rails 4.1 and RSpec are a bit on different pages on who should run migrations @@ -50,6 +49,7 @@ ::Devise.ldap_config = "#{Rails.root}/config/#{"ssl_" if ENV["LDAP_SSL"]}ldap.yml" ::Devise.ldap_check_group_membership = false ::Devise.ldap_check_attributes = false + ::Devise.ldap_check_attributes_presence = false ::Devise.ldap_auth_username_builder = Proc.new() {|attribute, login, ldap| "#{attribute}=#{login},#{ldap.base}" } ::Devise.authentication_keys = [:email] end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/unit/adapter_spec.rb new/spec/unit/adapter_spec.rb --- old/spec/unit/adapter_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/spec/unit/adapter_spec.rb 2018-02-13 19:06:27.000000000 +0100 @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe Devise::LDAP::Adapter do + describe '#expired_valid_credentials?' do + before do + ::Devise.ldap_use_admin_to_bind = true + expect_any_instance_of(Devise::LDAP::Connection).to receive(:expired_valid_credentials?) + end + + it 'can bind as the admin user' do + expect(Devise::LDAP::Connection).to receive(:new) + .with(hash_including( + :login => 'test.u...@test.com', + :password => 'pass', + :ldap_auth_username_builder => kind_of(Proc), + :admin => true)).and_call_original + + Devise::LDAP::Adapter.expired_valid_credentials?('test.u...@test.com', 'pass') + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/unit/connection_spec.rb new/spec/unit/connection_spec.rb --- old/spec/unit/connection_spec.rb 2015-06-19 18:22:40.000000000 +0200 +++ new/spec/unit/connection_spec.rb 2018-02-13 19:06:27.000000000 +0100 @@ -11,4 +11,93 @@ connection = Devise::LDAP::Connection.new() expect(connection.ldap.base).to eq('ou=testbase,dc=test,dc=com') end + + class TestOpResult + attr_accessor :error_message + end + + describe '#expired_valid_credentials?' do + let(:conn) { double(Net::LDAP).as_null_object } + let(:error) { } + let(:is_authed) { false } + before do + expect(Net::LDAP).to receive(:new).and_return(conn) + allow(conn).to receive(:get_operation_result).and_return(TestOpResult.new.tap{|r| r.error_message = error}) + allow_any_instance_of(Devise::LDAP::Connection).to receive(:authenticated?).and_return(is_authed) + allow_any_instance_of(Devise::LDAP::Connection).to receive(:dn).and_return('any dn') + expect(DeviseLdapAuthenticatable::Logger).to receive(:send).with('Authorizing user any dn') + end + subject do + Devise::LDAP::Connection.new.expired_valid_credentials? + end + + context do + let(:error) { 'THIS PART CAN BE ANYTHING AcceptSecurityContext error, data 773 SO CAN THIS' } + it 'is true when expired credential error is returned and not already authenticated' do + expect(subject).to be true + end + end + + context do + it 'is false when expired credential error is not returned and not already authenticated' do + expect(subject).to be false + end + end + + context do + let(:is_authed) { true } + it 'is false when expired credential error is not returned and already authenticated' do + expect(subject).to be false + end + end + end + + describe '#authorized?' do + let(:conn) { double(Net::LDAP).as_null_object } + let(:error) { } + let(:log_message) { } + let(:is_authed) { false } + before do + expect(Net::LDAP).to receive(:new).and_return(conn) + allow(conn).to receive(:get_operation_result).and_return(TestOpResult.new.tap{|r| r.error_message = error}) + allow_any_instance_of(Devise::LDAP::Connection).to receive(:authenticated?).and_return(is_authed) + allow_any_instance_of(Devise::LDAP::Connection).to receive(:dn).and_return('any dn') + expect(DeviseLdapAuthenticatable::Logger).to receive(:send).with('Authorizing user any dn') + end + subject do + Devise::LDAP::Connection.new.authorized? + end + context do + before { expect(DeviseLdapAuthenticatable::Logger).to receive(:send).with(log_message) } + + context do + let(:error) { 'THIS PART CAN BE ANYTHING AcceptSecurityContext error, data 52e SO CAN THIS' } + let(:log_message) { 'Not authorized because of invalid credentials.' } + it 'is false when credential error is returned' do + expect(subject).to be false + end + end + context do + let(:error) { 'THIS PART CAN BE ANYTHING AcceptSecurityContext error, data 773 SO CAN THIS' } + let(:log_message) { 'Not authorized because of expired credentials.' } + it 'is false when expired error is returned' do + expect(subject).to be false + end + end + context do + let(:error) { 'any error' } + let(:log_message) { 'Not authorized because not authenticated.' } + it 'is false when any other error is returned' do + expect(subject).to be false + end + end + end + + context do + let(:is_authed) { true } + it 'is true when already authenticated' do + expect(subject).to be true + end + end + end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/unit/user_spec.rb new/spec/unit/user_spec.rb --- old/spec/unit/user_spec.rb 2015-06-19 18:22:40.000000000 +0200 +++ new/spec/unit/user_spec.rb 2018-02-13 19:06:27.000000000 +0100 @@ -16,7 +16,7 @@ reset_ldap_server! end - describe "look up and ldap user" do + describe "look up an ldap user" do it "should return true for a user that does exist in LDAP" do assert_equal true, ::Devise::LDAP::Adapter.valid_login?('example.u...@test.com') end @@ -48,7 +48,7 @@ should_be_validated @user, "secret" @user.password = "changed" @user.change_password!("secret") - should_be_validated @user, "changed", "password was not changed properly on the LDAP sevrer" + should_be_validated @user, "changed", "password was not changed properly on the LDAP server" end it "should not allow to change password if setting is false" do @@ -80,7 +80,7 @@ it "should create a user in the database" do @user = User.find_for_ldap_authentication(:email => "example.u...@test.com", :password => "secret") assert_equal(User.all.size, 1) - User.all.collect(&:email).should include("example.u...@test.com") + expect(User.all.collect(&:email)).to include("example.u...@test.com") assert(@user.persisted?) end @@ -116,7 +116,7 @@ ::Devise.case_insensitive_keys = [:email] @user = User.find_for_ldap_authentication(:email => "example.u...@test.com", :password => "secret") - User.all.collect(&:email).should include("example.u...@test.com") + expect(User.all.collect(&:email)).to include("example.u...@test.com") end end @@ -135,32 +135,32 @@ end it "should admin should have the proper groups set" do - @admin.ldap_groups.should include('cn=admins,ou=groups,dc=test,dc=com') + expect(@admin.ldap_groups).to include('cn=admins,ou=groups,dc=test,dc=com') end it "should user should not be allowed in" do should_not_be_validated @user, "secret" end end - + describe "check group membership" do before do @admin = Factory.create(:admin) @user = Factory.create(:user) end - + it "should return true for admin being in the admins group" do assert_equal true, @admin.in_ldap_group?('cn=admins,ou=groups,dc=test,dc=com') end - + it "should return false for admin being in the admins group using the 'foobar' group attribute" do assert_equal false, @admin.in_ldap_group?('cn=admins,ou=groups,dc=test,dc=com', 'foobar') end - + it "should return true for user being in the users group" do assert_equal true, @user.in_ldap_group?('cn=users,ou=groups,dc=test,dc=com') - end - + end + it "should return false for user being in the admins group" do assert_equal false, @user.in_ldap_group?('cn=admins,ou=groups,dc=test,dc=com') end @@ -217,6 +217,26 @@ end end + describe "use attribute presence for authorization" do + before do + @admin = Factory.create(:admin) + @user = Factory.create(:user) + ::Devise.ldap_check_attributes_presence = true + end + + after do + ::Devise.ldap_check_attributes_presence = false + end + + it "should admin should not be allowed in" do + should_not_be_validated @admin, "admin_secret" + end + + it "should user should be allowed in" do + should_be_validated @user, "secret" + end + end + describe "use admin setting to bind" do before do @admin = Factory.create(:admin) @@ -229,6 +249,19 @@ end end + describe 'check password expiration' do + before { allow_any_instance_of(Devise::LDAP::Connection).to receive(:authenticated?).and_return(false) } + + it 'should return false for a user that has a fresh password' do + allow_any_instance_of(Devise::LDAP::Connection).to receive(:last_message_expired_credentials?).and_return(false) + assert_equal false, ::Devise::LDAP::Adapter.expired_valid_credentials?('example.u...@test.com','secret') + end + + it 'should return true for a user that has an expired password' do + allow_any_instance_of(Devise::LDAP::Connection).to receive(:last_message_expired_credentials?).and_return(true) + assert_equal true, ::Devise::LDAP::Adapter.expired_valid_credentials?('example.u...@test.com','secret') + end + end end describe "use uid for login" do @@ -259,7 +292,7 @@ it "should create a user in the database" do @user = User.find_for_ldap_authentication(:uid => "example_user", :password => "secret") assert_equal(User.all.size, 1) - User.all.collect(&:uid).should include("example_user") + expect(User.all.collect(&:uid)).to include("example_user") end it "should call ldap_before_save hooks" do