Merge branch 'master' into local-activedirectory-integration-testing

This commit is contained in:
Matt Todd 2014-11-14 14:26:48 -08:00
Родитель ec9021e095 b8407ed58a
Коммит f95f985f71
13 изменённых файлов: 276 добавлений и 49 удалений

13
CHANGELOG.md Normal file
Просмотреть файл

@ -0,0 +1,13 @@
# CHANGELOG
## v1.4.0
* Document constructor options [#57](https://github.com/github/github-ldap/pull/57)
* [CI] Add Vagrant box for running tests against OpenLDAP locally [#55](https://github.com/github/github-ldap/pull/55)
* Run all tests, including those in subdirectories [#54](https://github.com/github/github-ldap/pull/54)
* Add ActiveDirectory membership validator [#52](https://github.com/github/github-ldap/pull/52)
* Merge dev-v2 branch into master [#50](https://github.com/github/github-ldap/pull/50)
* Pass through search options for GitHub::Ldap::Domain#user? [#51](https://github.com/github/github-ldap/pull/51)
* Fix membership validation tests [#49](https://github.com/github/github-ldap/pull/49)
* Add CI build for OpenLDAP integration [#48](https://github.com/github/github-ldap/pull/48)
* Membership Validators [#45](https://github.com/github/github-ldap/pull/45)

Просмотреть файл

@ -130,3 +130,15 @@ end
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
## Releasing
This section is for gem maintainers to cut a new version of the gem. See
[jch/release-scripts](https://github.com/jch/release-scripts) for original
source of release scripts.
* Create a new branch from `master` named `release-x.y.z`, where `x.y.z` is the version to be released
* Update `github-ldap.gemspec` to x.y.z following [semver](http://semver.org)
* Run `script/changelog` and paste the draft into `CHANGELOG.md`. Edit as needed
* Create pull request to solict feedback
* After merging the pull request, on the master branch, run `script/release`

Просмотреть файл

@ -2,7 +2,7 @@
Gem::Specification.new do |spec|
spec.name = "github-ldap"
spec.version = "1.3.6"
spec.version = "1.4.0"
spec.authors = ["David Calavera"]
spec.email = ["david.calavera@gmail.com"]
spec.description = %q{Ldap authentication for humans}

Просмотреть файл

@ -34,6 +34,7 @@ module GitHub
def_delegator :@connection, :open
attr_reader :uid, :search_domains, :virtual_attributes,
:membership_validator,
:instrumentation_service
# Build a new GitHub::Ldap instance
@ -87,6 +88,9 @@ module GitHub
# when a base is not explicitly provided.
@search_domains = Array(options[:search_domains])
# configure which strategy should be used to validate user membership
configure_membership_validation_strategy(options[:membership_validator])
# enables instrumenting queries
@instrumentation_service = options[:instrumentation_service]
end
@ -182,6 +186,23 @@ module GitHub
end
end
# Internal: Searches the host LDAP server's Root DSE for capabilities and
# extensions.
#
# Returns a Net::LDAP::Entry object.
def capabilities
@capabilities ||=
instrument "capabilities.github_ldap" do |payload|
begin
@connection.search_root_dse
rescue Net::LDAP::LdapError => error
payload[:error] = error
# stubbed result
Net::LDAP::Entry.new
end
end
end
# Internal - Determine whether to use encryption or not.
#
# encryption: is the encryption method, either 'ssl', 'tls', 'simple_tls' or 'start_tls'.
@ -214,5 +235,24 @@ module GitHub
VirtualAttributes.new(false)
end
end
# Internal: Configure the membership validation strategy.
#
# Used by GitHub::Ldap::MembershipValidators::Detect to force a specific
# strategy (instead of detecting host capabilities and deciding at runtime).
#
# If `strategy` is not provided, or doesn't match a known strategy,
# defaults to `:detect`. Otherwise the configured strategy is selected.
#
# Returns the selected membership validator strategy Symbol.
def configure_membership_validation_strategy(strategy = nil)
@membership_validator =
case strategy.to_s
when "classic", "recursive", "active_directory"
strategy.to_sym
else
:detect
end
end
end
end

Просмотреть файл

@ -1,4 +1,5 @@
require 'github/ldap/membership_validators/base'
require 'github/ldap/membership_validators/detect'
require 'github/ldap/membership_validators/classic'
require 'github/ldap/membership_validators/recursive'
require 'github/ldap/membership_validators/active_directory'
@ -13,6 +14,13 @@ module GitHub
# validator = GitHub::Ldap::MembershipValidators::Classic.new(ldap, groups)
# validator.perform(entry) #=> true
#
module MembershipValidators; end
module MembershipValidators
# Internal: Mapping of strategy name to class.
STRATEGIES = {
:classic => GitHub::Ldap::MembershipValidators::Classic,
:recursive => GitHub::Ldap::MembershipValidators::Recursive,
:active_directory => GitHub::Ldap::MembershipValidators::ActiveDirectory
}
end
end
end

Просмотреть файл

@ -0,0 +1,69 @@
module GitHub
class Ldap
module MembershipValidators
# Detects the LDAP host's capabilities and determines the appropriate
# membership validation strategy at runtime. Currently detects for
# ActiveDirectory in-chain membership validation. An explicit strategy can
# also be defined via `GitHub::Ldap#membership_validator=`. See also
# `GitHub::Ldap#configure_membership_validation_strategy`.
class Detect < Base
# Internal: The capability required to use the ActiveDirectory strategy.
# See: http://msdn.microsoft.com/en-us/library/cc223359.aspx.
ACTIVE_DIRECTORY_V61_R2_OID = "1.2.840.113556.1.4.2080".freeze
def perform(entry)
# short circuit validation if there are no groups to check against
return true if groups.empty?
strategy.perform(entry)
end
# Internal: Returns the membership validation strategy object.
def strategy
@strategy ||= begin
strategy = detect_strategy
strategy.new(ldap, groups)
end
end
# Internal: Detects LDAP host's capabilities and chooses the best
# strategy for the host.
#
# If the strategy has been set explicitly, skips detection and uses the
# configured strategy instead.
#
# Returns the strategy class.
def detect_strategy
case
when GitHub::Ldap::MembershipValidators::STRATEGIES.key?(strategy_config)
GitHub::Ldap::MembershipValidators::STRATEGIES[strategy_config]
when active_directory_capability?
GitHub::Ldap::MembershipValidators::STRATEGIES[:active_directory]
else
GitHub::Ldap::MembershipValidators::STRATEGIES[:recursive]
end
end
# Internal: Returns the configured membership validator strategy Symbol.
def strategy_config
ldap.membership_validator
end
# Internal: Detect whether the LDAP host is an ActiveDirectory server.
#
# See: http://msdn.microsoft.com/en-us/library/cc223359.aspx.
#
# Returns true if the host is an ActiveDirectory server, false otherwise.
def active_directory_capability?
capabilities[:supportedcapabilities].include?(ACTIVE_DIRECTORY_V61_R2_OID)
end
# Internal: Returns the Net::LDAP::Entry object describing the LDAP
# host's capabilities (via the Root DSE).
def capabilities
ldap.capabilities
end
end
end
end
end

29
script/changelog Executable file
Просмотреть файл

@ -0,0 +1,29 @@
#!/usr/bin/env sh
# Usage: script/changelog [-r <repo>] [-b <base>] [-h <head>]
#
# repo: base string of GitHub repository url. e.g. "user_or_org/repository". Defaults to git remote url.
# base: git ref to compare from. e.g. "v1.3.1". Defaults to latest git tag.
# head: git ref to compare to. Defaults to "HEAD".
#
# Generate a changelog preview from pull requests merged between `base` and
# `head`.
#
set -e
[ $# -eq 0 ] && set -- --help
# parse args
repo=$(git remote -v | grep push | awk '{print $2}' | cut -d'/' -f4-)
base=$(git tag -l | sort -n | tail -n 1)
head="HEAD"
api_url="https://api.github.com"
echo "# $base..$head"
echo
# get merged PR's. Better way is to query the API for these, but this is easier
for pr in $(git log --oneline v1.3.6..HEAD | grep "Merge pull request" | awk '{gsub("#",""); print $5}')
do
# frustrated with trying to pull out the right values, fell back to ruby
curl -s "$api_url/repos/$repo/pulls/$pr" | ruby -rjson -e 'pr=JSON.parse(STDIN.read); puts "* #{pr[%q(title)]} [##{pr[%q(number)]}](#{pr[%q(html_url)]})"'
done

7
script/package Executable file
Просмотреть файл

@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Usage: script/package
# Updates the gemspec and builds a new gem in the pkg directory.
mkdir -p pkg
gem build *.gemspec
mv *.gem pkg

16
script/release Executable file
Просмотреть файл

@ -0,0 +1,16 @@
#!/usr/bin/env bash
# Usage: script/release
# Build the package, tag a commit, push it to origin, and then release the
# package publicly.
set -e
version="$(script/package | grep Version: | awk '{print $2}')"
[ -n "$version" ] || exit 1
echo $version
git commit --allow-empty -a -m "Release $version"
git tag "v$version"
git push origin
git push origin "v$version"
gem push pkg/*-${version}.gem

Просмотреть файл

@ -72,6 +72,34 @@ module GitHubLdapTestCases
assert_equal "(uid=user1)", payload[:filter].to_s
assert_equal "dc=github,dc=com", payload[:base]
end
def test_membership_validator_default
assert_equal :detect, @ldap.membership_validator
end
def test_membership_validator_configured_to_classic_strategy
@ldap.configure_membership_validation_strategy :classic
assert_equal :classic, @ldap.membership_validator
end
def test_membership_validator_configured_to_recursive_strategy
@ldap.configure_membership_validation_strategy :recursive
assert_equal :recursive, @ldap.membership_validator
end
def test_membership_validator_configured_to_active_directory_strategy
@ldap.configure_membership_validation_strategy :active_directory
assert_equal :active_directory, @ldap.membership_validator
end
def test_membership_validator_misconfigured_to_unrecognized_strategy_falls_back_to_default
@ldap.configure_membership_validation_strategy :unknown
assert_equal :detect, @ldap.membership_validator
end
def test_capabilities
assert_kind_of Net::LDAP::Entry, @ldap.capabilities
end
end
class GitHubLdapTest < GitHub::Ldap::Test

Просмотреть файл

@ -0,0 +1,49 @@
require_relative '../test_helper'
# NOTE: Since this strategy is targeted at detecting ActiveDirectory
# capabilities, and we don't have AD setup in CI, we stub out actual queries
# and test against what AD *would* respond with.
class GitHubLdapDetectMembershipValidatorsTest < GitHub::Ldap::Test
def setup
@ldap = GitHub::Ldap.new(options.merge(search_domains: %w(dc=github,dc=com)))
@domain = @ldap.domain("dc=github,dc=com")
@entry = @domain.user?('user1')
@validator = GitHub::Ldap::MembershipValidators::Detect
end
def make_validator(groups)
groups = @domain.groups(groups)
@validator.new(@ldap, groups)
end
def test_defers_to_configured_strategy
@ldap.configure_membership_validation_strategy(:classic)
validator = make_validator(%w(group))
assert_kind_of GitHub::Ldap::MembershipValidators::Classic, validator.strategy
end
def test_detects_active_directory
caps = Net::LDAP::Entry.new
caps[:supportedcapabilities] =
[GitHub::Ldap::MembershipValidators::Detect::ACTIVE_DIRECTORY_V61_R2_OID]
validator = make_validator(%w(group))
@ldap.stub :capabilities, caps do
assert_kind_of GitHub::Ldap::MembershipValidators::ActiveDirectory,
validator.strategy
end
end
def test_falls_back_to_recursive
caps = Net::LDAP::Entry.new
caps[:supportedcapabilities] = []
validator = make_validator(%w(group))
@ldap.stub :capabilities, caps do
assert_kind_of GitHub::Ldap::MembershipValidators::Recursive,
validator.strategy
end
end
end

Просмотреть файл

@ -1,46 +0,0 @@
require_relative 'test_helper'
module GitHubLdapMembershipValidatorsTestCases
def make_validator(groups)
groups = @domain.groups(groups)
@validator.new(@ldap, groups)
end
def test_validates_user_in_group
validator = make_validator(%w(ghe-users))
assert validator.perform(@entry)
end
def test_does_not_validate_user_not_in_group
validator = make_validator(%w(ghe-admins))
refute validator.perform(@entry)
end
def test_does_not_validate_user_not_in_any_group
@entry = @domain.user?('groupless-user1')
validator = make_validator(%w(ghe-users ghe-admins))
refute validator.perform(@entry)
end
end
class GitHubLdapMembershipValidatorsClassicTest < GitHub::Ldap::Test
include GitHubLdapMembershipValidatorsTestCases
def setup
@ldap = GitHub::Ldap.new(options.merge(search_domains: "dc=github,dc=com"))
@domain = @ldap.domain("dc=github,dc=com")
@entry = @domain.user?('user1')
@validator = GitHub::Ldap::MembershipValidators::Classic
end
end
class GitHubLdapMembershipValidatorsRecursiveTest < GitHub::Ldap::Test
include GitHubLdapMembershipValidatorsTestCases
def setup
@ldap = GitHub::Ldap.new(options.merge(search_domains: "dc=github,dc=com"))
@domain = @ldap.domain("dc=github,dc=com")
@entry = @domain.user?('user1')
@validator = GitHub::Ldap::MembershipValidators::Recursive
end
end

4
test/support/vm/openldap/Vagrantfile поставляемый
Просмотреть файл

@ -13,7 +13,8 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.ssh.forward_agent = true
config.vm.provision "shell", inline: "apt-get update; exec env /vagrant_data/script/install-openldap"
# config.vm.provision "shell", inline: "apt-get update; exec env /vagrant_data/script/install-openldap"
config.vm.provision "shell", inline: 'echo "HIIIIIII"', run: "always"
config.vm.synced_folder "../../../..", "/vagrant_data"
@ -30,4 +31,5 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
vb.customize ["modifyvm", :id, "--chipset", "ich9"]
vb.customize ["modifyvm", :id, "--vram", "16"]
end
end