Merge branch 'master' into local-activedirectory-integration-testing
This commit is contained in:
Коммит
f95f985f71
|
@ -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)
|
12
README.md
12
README.md
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче