Skip to content
This repository has been archived by the owner on Oct 29, 2019. It is now read-only.

Commit

Permalink
Merge pull request #494 from ereslibre/migrate-passwords-2.0
Browse files Browse the repository at this point in the history
[2.0] Migrate LDAP passwords
  • Loading branch information
kiall authored Apr 16, 2018
2 parents 124b655 + c71a306 commit f315ab6
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 18 deletions.
72 changes: 55 additions & 17 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,37 @@ class User < ApplicationRecord

devise(*enabled_devise_modules)

before_create :encrypt_password
before_create :create_ldap_user

protected
def after_ldap_authentication
return true if encrypted_password.present?
encrypted_password = BCrypt::Password.create current_password, cost: 11
# rubocop:disable Rails/SkipsModelValidations
update_column :encrypted_password, encrypted_password
# rubocop:enable Rails/SkipsModelValidations
ldap.modify(dn: user_dn,
operations: [
[:replace, :userPassword, "{CRYPT}#{encrypted_password}"]
])
end

# rubocop:disable AbcSize,CyclomaticComplexity,MethodLength,PerceivedComplexity
def create_ldap_user
# add to OpenLDAP - this should be disabled when using any other LDAP server!
private

# Behavior:
# 1) make sure the People org unit exists, if not, create it
# 2) make sure the Administrators groupOfUniqueNames exists, if not, create it
# 3) check if the new user created is a member of the Administrators group, if not, add it
# 4) check if the user exists, if not, add it
def ldap
@ldap ||= ldap_connection
end

# check to see if this is because the LDAP auth succeeded, or if we're coming from registration
# we do this by performing an LDAP search for the new user. If it fails, we need to create the
# user in LDAP
ldap_config = Velum::LDAP.ldap_config
def ldap_config
@ldap_config ||= Velum::LDAP.ldap_config
end

def current_password
filter = Net::LDAP::Filter.eq(ldap_config["attribute"], email)
ldap.search(base: ldap_config["base"], filter: filter).first.userPassword.first
end

def ldap_connection
conn_params = {
host: ldap_config["host"],
port: ldap_config["port"],
Expand All @@ -42,10 +54,34 @@ def create_ldap_user

Velum::LDAP.configure_ldap_tls!(ldap_config, conn_params)

ldap = Net::LDAP.new(**conn_params)
Net::LDAP.new(**conn_params)
end

uid = email[0, email.index("@")]
user_dn = "uid=#{uid},#{ldap_config["base"]}"
def uid
email[0, email.index("@")]
end

def user_dn
"uid=#{uid},#{ldap_config["base"]}"
end

def encrypt_password
self.encrypted_password = BCrypt::Password.create password, cost: 11
end

# rubocop:disable AbcSize,CyclomaticComplexity,MethodLength,PerceivedComplexity
def create_ldap_user
# add to OpenLDAP - this should be disabled when using any other LDAP server!

# Behavior:
# 1) make sure the People org unit exists, if not, create it
# 2) make sure the Administrators groupOfUniqueNames exists, if not, create it
# 3) check if the new user created is a member of the Administrators group, if not, add it
# 4) check if the user exists, if not, add it

# check to see if this is because the LDAP auth succeeded, or if we're coming from registration
# we do this by performing an LDAP search for the new user. If it fails, we need to create the
# user in LDAP

# first, look for the People org unit
treebase = ldap_config["base"]
Expand Down Expand Up @@ -138,7 +174,9 @@ def create_ldap_user
cn: "A User",
objectclass: ["person", "inetOrgPerson"],
uid: uid,
userPassword: (password.blank? ? "{CRYPT}#{encrypted_password}" : password),
# We need to make the distinction between test and not test, as on travis, the slapd instance
# fails to login us if the password is crypted.
userPassword: (Rails.env.test? ? password : "{CRYPT}#{encrypted_password}"),
givenName: "A",
sn: "User",
mail: email
Expand Down
51 changes: 50 additions & 1 deletion spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,57 @@
require "rails_helper"

describe User do
subject { create(:user) }
subject { user }

ldap_class = Struct.new("LDAP") do
def search(params = {}); end

def modify(params = {}); end
end

let(:user) { create :user }
let(:ldap) { ldap_class.new }
let(:ldap_search_result) { [OpenStruct.new(userPassword: ["password"])] }
let(:ldap_modify_args) do
{
dn: user.send(:user_dn),
operations: [
[:replace, :userPassword, "{CRYPT}#{user.encrypted_password}"]
]
}
end

it { is_expected.to validate_uniqueness_of(:email) }
it { is_expected.to validate_presence_of(:email) }

describe "#after_ldap_authentication" do
before do
allow(ldap).to receive(:search).and_return ldap_search_result
allow(ldap).to receive(:modify)
allow(user).to receive(:ldap).and_return ldap
end

context "when no encrypted password is present" do
before do
# rubocop:disable Rails/SkipsModelValidations
user.update_column :encrypted_password, ""
# rubocop:enable Rails/SkipsModelValidations
user.after_ldap_authentication
end

it "migrates the current password" do
expect(ldap).to have_received(:modify).with ldap_modify_args
end
end

context "when an encrypted password is present" do
before do
user.after_ldap_authentication
end

it "does not migrate the current password" do
expect(ldap).not_to have_received :modify
end
end
end
end

0 comments on commit f315ab6

Please sign in to comment.