gitlab_omniauth-ldap 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .project
2
+ coverage
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ branches:
2
+ only:
3
+ - 'master'
4
+ rvm:
5
+ - 1.9.2
6
+ script: "bundle exec rspec spec"
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem 'rspec'
7
+ gem 'pry'
8
+ gem 'rake'
9
+ gem 'rack-test'
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ gitlab_omniauth-ldap (1.0.2)
5
+ net-ldap (~> 0.2.2)
6
+ omniauth (~> 1.0)
7
+ pyu-ruby-sasl (~> 0.0.3.1)
8
+ rubyntlm (~> 0.1.1)
9
+
10
+ GEM
11
+ remote: http://rubygems.org/
12
+ specs:
13
+ coderay (1.0.8)
14
+ diff-lcs (1.1.3)
15
+ hashie (1.2.0)
16
+ method_source (0.8.1)
17
+ net-ldap (0.2.2)
18
+ omniauth (1.1.1)
19
+ hashie (~> 1.2)
20
+ rack
21
+ pry (0.9.10)
22
+ coderay (~> 1.0.5)
23
+ method_source (~> 0.8)
24
+ slop (~> 3.3.1)
25
+ pyu-ruby-sasl (0.0.3.3)
26
+ rack (1.4.1)
27
+ rack-test (0.6.2)
28
+ rack (>= 1.0)
29
+ rake (10.0.3)
30
+ rspec (2.12.0)
31
+ rspec-core (~> 2.12.0)
32
+ rspec-expectations (~> 2.12.0)
33
+ rspec-mocks (~> 2.12.0)
34
+ rspec-core (2.12.2)
35
+ rspec-expectations (2.12.1)
36
+ diff-lcs (~> 1.1.3)
37
+ rspec-mocks (2.12.1)
38
+ rubyntlm (0.1.1)
39
+ slop (3.3.3)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ gitlab_omniauth-ldap!
46
+ pry
47
+ rack-test
48
+ rake
49
+ rspec
data/Guardfile ADDED
@@ -0,0 +1,11 @@
1
+ guard 'rspec', :version => 2 do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
6
+
7
+
8
+ guard 'bundler' do
9
+ watch('Gemfile')
10
+ watch(/^.+\.gemspec/)
11
+ end
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # GitLab fork | OmniAuth LDAP [![build status](https://secure.travis-ci.org/gitlabhq/omniauth-ldap.png)](https://travis-ci.org/gitlabhq/omniauth-ldap)
2
+
3
+ ### LDAP
4
+
5
+ Use the LDAP strategy as a middleware in your application:
6
+
7
+ use OmniAuth::Strategies::LDAP,
8
+ :title => "My LDAP",
9
+ :host => '10.101.10.1',
10
+ :port => 389,
11
+ :method => :plain,
12
+ :base => 'dc=intridea, dc=com',
13
+ :uid => 'sAMAccountName',
14
+ :name_proc => Proc.new {|name| name.gsub(/@.*$/,'')}
15
+ :bind_dn => 'default_bind_dn'
16
+ :password => 'password'
17
+
18
+ All of the listed options are required, with the exception of :title, :name_proc, :bind_dn, and :password.
19
+ Allowed values of :method are: :plain, :ssl, :tls.
20
+
21
+ :bind_dn and :password is the default credentials to perform user lookup.
22
+ most LDAP servers require that you supply a complete DN as a binding-credential, along with an authenticator
23
+ such as a password. But for many applications, you often don’t have a full DN to identify the user.
24
+ You usually get a simple identifier like a username or an email address, along with a password.
25
+ Since many LDAP servers don't allow anonymous access, search function will require a bound connection,
26
+ :bind_dn and :password will be required for searching on the username or email to retrieve the DN attribute
27
+ for the user. If the LDAP server allows anonymous access, you don't need to provide these two parameters.
28
+
29
+ :uid is the LDAP attribute name for the user name in the login form.
30
+ typically AD would be 'sAMAccountName' or 'UserPrincipalName', while OpenLDAP is 'uid'.
31
+
32
+ :name_proc allows you to match the user name entered with the format of the :uid attributes.
33
+ For example, value of 'sAMAccountName' in AD contains only the windows user name. If your user prefers using
34
+ email to login, a name_proc as above will trim the email string down to just the windows login name.
35
+ In summary, use :name_proc to fill the gap between the submitted username and LDAP uid attribute value.
36
+
37
+ :try_sasl and :sasl_mechanisms are optional. :try_sasl [true | false], :sasl_mechanisms ['DIGEST-MD5' | 'GSS-SPNEGO']
38
+ Use them to initialize a SASL connection to server. If you are not familiar with these authentication methods,
39
+ please just avoid them.
40
+
41
+ Direct users to '/auth/ldap' to have them authenticated via your company's LDAP server.
42
+
43
+
44
+ ## License
45
+
46
+ Copyright (C) 2011 by Ping Yu and Intridea, Inc.
47
+
48
+ Permission is hereby granted, free of charge, to any person obtaining a copy
49
+ of this software and associated documentation files (the "Software"), to deal
50
+ in the Software without restriction, including without limitation the rights
51
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
52
+ copies of the Software, and to permit persons to whom the Software is
53
+ furnished to do so, subject to the following conditions:
54
+
55
+ The above copyright notice and this permission notice shall be included in
56
+ all copies or substantial portions of the Software.
57
+
58
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
64
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc 'Default: run specs.'
6
+ task :default => :spec
7
+
8
+ desc "Run specs"
9
+ RSpec::Core::RakeTask.new
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/omniauth-ldap/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Ping Yu"]
6
+ gem.email = ["ping@intridea.com"]
7
+ gem.description = %q{A LDAP strategy for OmniAuth.}
8
+ gem.summary = %q{A LDAP strategy for OmniAuth.}
9
+ gem.homepage = "https://github.com/gitlabhq/omniauth-ldap"
10
+
11
+ gem.add_runtime_dependency 'omniauth', '~> 1.0'
12
+ gem.add_runtime_dependency 'net-ldap', '~> 0.2.2'
13
+ gem.add_runtime_dependency 'pyu-ruby-sasl', '~> 0.0.3.1'
14
+ gem.add_runtime_dependency 'rubyntlm', '~> 0.1.1'
15
+
16
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ gem.files = `git ls-files`.split("\n")
18
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ gem.name = "gitlab_omniauth-ldap"
20
+ gem.require_paths = ["lib"]
21
+ gem.version = OmniAuth::LDAP::VERSION
22
+ end
@@ -0,0 +1,93 @@
1
+ require 'omniauth'
2
+
3
+ module OmniAuth
4
+ module Strategies
5
+ class LDAP
6
+ class MissingCredentialsError < StandardError; end
7
+ include OmniAuth::Strategy
8
+ @@config = {
9
+ 'name' => 'cn',
10
+ 'first_name' => 'givenName',
11
+ 'last_name' => 'sn',
12
+ 'email' => ['mail', "email", 'userPrincipalName'],
13
+ 'phone' => ['telephoneNumber', 'homePhone', 'facsimileTelephoneNumber'],
14
+ 'mobile' => ['mobile', 'mobileTelephoneNumber'],
15
+ 'nickname' => ['uid', 'userid', 'sAMAccountName'],
16
+ 'title' => 'title',
17
+ 'location' => {"%0, %1, %2, %3 %4" => [['address', 'postalAddress', 'homePostalAddress', 'street', 'streetAddress'], ['l'], ['st'],['co'],['postOfficeBox']]},
18
+ 'uid' => 'dn',
19
+ 'url' => ['wwwhomepage'],
20
+ 'image' => 'jpegPhoto',
21
+ 'description' => 'description'
22
+ }
23
+ option :title, "LDAP Authentication" #default title for authentication form
24
+ option :port, 389
25
+ option :method, :plain
26
+ option :uid, 'sAMAccountName'
27
+ option :name_proc, lambda {|n| n}
28
+
29
+ def request_phase
30
+ OmniAuth::LDAP::Adaptor.validate @options
31
+ f = OmniAuth::Form.new(:title => (options[:title] || "LDAP Authentication"), :url => callback_path)
32
+ f.text_field 'Login', 'username'
33
+ f.password_field 'Password', 'password'
34
+ f.button "Sign In"
35
+ f.to_response
36
+ end
37
+
38
+ def callback_phase
39
+ @adaptor = OmniAuth::LDAP::Adaptor.new @options
40
+
41
+ begin
42
+ # GITLAB security patch
43
+ # Dont allow blank password for ldap auth
44
+ if request['username'].nil? || request['username'].empty? || request['password'].nil? || request['password'].empty?
45
+ raise MissingCredentialsError.new("Missing login credentials")
46
+ end
47
+
48
+ @ldap_user_info = @adaptor.bind_as(:filter => Net::LDAP::Filter.eq(@adaptor.uid, @options[:name_proc].call(request['username'])),:size => 1, :password => request['password'])
49
+ return fail!(:invalid_credentials) if !@ldap_user_info
50
+
51
+ @user_info = self.class.map_user(@@config, @ldap_user_info)
52
+ super
53
+ rescue Exception => e
54
+ return fail!(:ldap_error, e)
55
+ end
56
+ end
57
+
58
+ uid {
59
+ @user_info["uid"]
60
+ }
61
+ info {
62
+ @user_info
63
+ }
64
+ extra {
65
+ { :raw_info => @ldap_user_info }
66
+ }
67
+
68
+ def self.map_user(mapper, object)
69
+ user = {}
70
+ mapper.each do |key, value|
71
+ case value
72
+ when String
73
+ user[key] = object[value.downcase.to_sym].first if object[value.downcase.to_sym]
74
+ when Array
75
+ value.each {|v| (user[key] = object[v.downcase.to_sym].first; break;) if object[v.downcase.to_sym]}
76
+ when Hash
77
+ value.map do |key1, value1|
78
+ pattern = key1.dup
79
+ value1.each_with_index do |v,i|
80
+ part = ''; v.collect(&:downcase).collect(&:to_sym).each {|v1| (part = object[v1].first; break;) if object[v1]}
81
+ pattern.gsub!("%#{i}",part||'')
82
+ end
83
+ user[key] = pattern
84
+ end
85
+ end
86
+ end
87
+ user
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ OmniAuth.config.add_camelization 'ldap', 'LDAP'
@@ -0,0 +1,149 @@
1
+ #this code borrowed pieces from activeldap and net-ldap
2
+
3
+ require 'rack'
4
+ require 'net/ldap'
5
+ require 'net/ntlm'
6
+ require 'uri'
7
+ require 'sasl'
8
+ require 'kconv'
9
+ module OmniAuth
10
+ module LDAP
11
+ class Adaptor
12
+ class LdapError < StandardError; end
13
+ class ConfigurationError < StandardError; end
14
+ class AuthenticationError < StandardError; end
15
+ class ConnectionError < StandardError; end
16
+
17
+ VALID_ADAPTER_CONFIGURATION_KEYS = [:host, :port, :method, :bind_dn, :password, :try_sasl, :sasl_mechanisms, :uid, :base, :allow_anonymous]
18
+
19
+ MUST_HAVE_KEYS = [:host, :port, :method, :uid, :base]
20
+
21
+ METHOD = {
22
+ :ssl => :simple_tls,
23
+ :tls => :start_tls,
24
+ :plain => nil,
25
+ }
26
+
27
+ attr_accessor :bind_dn, :password
28
+ attr_reader :connection, :uid, :base, :auth
29
+ def self.validate(configuration={})
30
+ message = []
31
+ MUST_HAVE_KEYS.each do |name|
32
+ message << name if configuration[name].nil?
33
+ end
34
+ raise ArgumentError.new(message.join(",") +" MUST be provided") unless message.empty?
35
+ end
36
+ def initialize(configuration={})
37
+ Adaptor.validate(configuration)
38
+ @configuration = configuration.dup
39
+ @configuration[:allow_anonymous] ||= false
40
+ @logger = @configuration.delete(:logger)
41
+ VALID_ADAPTER_CONFIGURATION_KEYS.each do |name|
42
+ instance_variable_set("@#{name}", @configuration[name])
43
+ end
44
+ method = ensure_method(@method)
45
+ config = {
46
+ :host => @host,
47
+ :port => @port,
48
+ :encryption => method,
49
+ :base => @base
50
+ }
51
+ @uri = construct_uri(@host, @port, @method != :plain)
52
+
53
+ @bind_method = @try_sasl ? :sasl : (@allow_anonymous||!@bind_dn||!@password ? :anonymous : :simple)
54
+
55
+
56
+ @auth = sasl_auths({:username => @bind_dn, :password => @password}).first if @bind_method == :sasl
57
+ @auth ||= { :method => @bind_method,
58
+ :username => @bind_dn,
59
+ :password => @password
60
+ }
61
+ config[:auth] = @auth
62
+ @connection = Net::LDAP.new(config)
63
+ end
64
+
65
+ #:base => "dc=yourcompany, dc=com",
66
+ # :filter => "(mail=#{user})",
67
+ # :password => psw
68
+ def bind_as(args = {})
69
+ result = false
70
+ @connection.open do |me|
71
+ rs = me.search args
72
+ if rs and rs.first and dn = rs.first.dn
73
+ password = args[:password]
74
+ method = args[:method] || @method
75
+ password = password.call if password.respond_to?(:call)
76
+ if method == 'sasl'
77
+ result = rs.first if me.bind(sasl_auths({:username => dn, :password => password}).first)
78
+ else
79
+ result = rs.first if me.bind(:method => :simple, :username => dn,
80
+ :password => password)
81
+ end
82
+ end
83
+ end
84
+ result
85
+ end
86
+
87
+ private
88
+ def ensure_method(method)
89
+ method ||= "plain"
90
+ normalized_method = method.to_s.downcase.to_sym
91
+ return METHOD[normalized_method] if METHOD.has_key?(normalized_method)
92
+
93
+ available_methods = METHOD.keys.collect {|m| m.inspect}.join(", ")
94
+ format = "%s is not one of the available connect methods: %s"
95
+ raise ConfigurationError, format % [method.inspect, available_methods]
96
+ end
97
+
98
+ def sasl_auths(options={})
99
+ auths = []
100
+ sasl_mechanisms = options[:sasl_mechanisms] || @sasl_mechanisms
101
+ sasl_mechanisms.each do |mechanism|
102
+ normalized_mechanism = mechanism.downcase.gsub(/-/, '_')
103
+ sasl_bind_setup = "sasl_bind_setup_#{normalized_mechanism}"
104
+ next unless respond_to?(sasl_bind_setup, true)
105
+ initial_credential, challenge_response = send(sasl_bind_setup, options)
106
+ auths << {
107
+ :method => :sasl,
108
+ :initial_credential => initial_credential,
109
+ :mechanism => mechanism,
110
+ :challenge_response => challenge_response
111
+ }
112
+ end
113
+ auths
114
+ end
115
+
116
+ def sasl_bind_setup_digest_md5(options)
117
+ bind_dn = options[:username]
118
+ initial_credential = ""
119
+ challenge_response = Proc.new do |cred|
120
+ pref = SASL::Preferences.new :digest_uri => "ldap/#{@host}", :username => bind_dn, :has_password? => true, :password => options[:password]
121
+ sasl = SASL.new("DIGEST-MD5", pref)
122
+ response = sasl.receive("challenge", cred)
123
+ response[1]
124
+ end
125
+ [initial_credential, challenge_response]
126
+ end
127
+
128
+ def sasl_bind_setup_gss_spnego(options)
129
+ bind_dn = options[:username]
130
+ psw = options[:password]
131
+ raise LdapError.new( "invalid binding information" ) unless (bind_dn && psw)
132
+
133
+ nego = proc {|challenge|
134
+ t2_msg = Net::NTLM::Message.parse( challenge )
135
+ bind_dn, domain = bind_dn.split('\\').reverse
136
+ t2_msg.target_name = Net::NTLM::encode_utf16le(domain) if domain
137
+ t3_msg = t2_msg.response( {:user => bind_dn, :password => psw}, {:ntlmv2 => true} )
138
+ t3_msg.serialize
139
+ }
140
+ [Net::NTLM::Message::Type1.new.serialize, nego]
141
+ end
142
+
143
+ def construct_uri(host, port, ssl)
144
+ protocol = ssl ? "ldaps" : "ldap"
145
+ URI.parse("#{protocol}://#{host}:#{port}").to_s
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,5 @@
1
+ module OmniAuth
2
+ module LDAP
3
+ VERSION = "1.0.2"
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ require "omniauth-ldap/version"
2
+ require "omniauth-ldap/adaptor"
3
+ require 'omniauth/strategies/ldap'
4
+
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ describe "OmniAuth::Strategies::LDAP" do
4
+ # :title => "My LDAP",
5
+ # :host => '10.101.10.1',
6
+ # :port => 389,
7
+ # :method => :plain,
8
+ # :base => 'dc=intridea, dc=com',
9
+ # :uid => 'sAMAccountName',
10
+ # :name_proc => Proc.new {|name| name.gsub(/@.*$/,'')}
11
+ # :bind_dn => 'default_bind_dn'
12
+ # :password => 'password'
13
+ class MyLdapProvider < OmniAuth::Strategies::LDAP; end
14
+
15
+ def app
16
+ Rack::Builder.new {
17
+ use OmniAuth::Test::PhonySession
18
+ use MyLdapProvider, :name => 'ldap', :title => 'MyLdap Form', :host => '192.168.1.145', :base => 'dc=score, dc=local', :name_proc => Proc.new {|name| name.gsub(/@.*$/,'')}
19
+ run lambda { |env| [404, {'Content-Type' => 'text/plain'}, [env.key?('omniauth.auth').to_s]] }
20
+ }.to_app
21
+ end
22
+
23
+ def session
24
+ last_request.env['rack.session']
25
+ end
26
+
27
+ it 'should add a camelization for itself' do
28
+ OmniAuth::Utils.camelize('ldap').should == 'LDAP'
29
+ end
30
+
31
+ describe '/auth/ldap' do
32
+ before(:each){ get '/auth/ldap' }
33
+
34
+ it 'should display a form' do
35
+ last_response.status.should == 200
36
+ last_response.body.should be_include("<form")
37
+ end
38
+
39
+ it 'should have the callback as the action for the form' do
40
+ last_response.body.should be_include("action='/auth/ldap/callback'")
41
+ end
42
+
43
+ it 'should have a text field for each of the fields' do
44
+ last_response.body.scan('<input').size.should == 2
45
+ end
46
+ it 'should have a label of the form title' do
47
+ last_response.body.scan('MyLdap Form').size.should > 1
48
+ end
49
+
50
+ end
51
+
52
+ describe 'post /auth/ldap/callback' do
53
+ before(:each) do
54
+ @adaptor = mock(OmniAuth::LDAP::Adaptor, {:uid => 'ping'})
55
+ OmniAuth::LDAP::Adaptor.stub(:new).and_return(@adaptor)
56
+ end
57
+
58
+ context 'failure' do
59
+ before(:each) do
60
+ @adaptor.stub(:bind_as).and_return(false)
61
+ end
62
+
63
+ it 'should raise MissingCredentialsError' do
64
+ post('/auth/ldap/callback', {})
65
+ last_response.should be_redirect
66
+ last_response.headers['Location'].should =~ %r{ldap_error}
67
+ end
68
+
69
+ it 'should redirect to error page' do
70
+ post('/auth/ldap/callback', {:username => 'ping', :password => 'password'})
71
+ last_response.should be_redirect
72
+ last_response.headers['Location'].should =~ %r{invalid_credentials}
73
+ end
74
+
75
+ it 'should redirect to error page when there is exception' do
76
+ @adaptor.stub(:bind_as).and_throw(Exception.new('connection_error'))
77
+ post('/auth/ldap/callback', {:username => 'ping', :password => 'password'})
78
+ last_response.should be_redirect
79
+ last_response.headers['Location'].should =~ %r{ldap_error}
80
+ end
81
+ end
82
+
83
+ context 'success' do
84
+ let(:auth_hash){ last_request.env['omniauth.auth'] }
85
+ before(:each) do
86
+ @adaptor.stub(:bind_as).and_return({:dn => ['cn=ping, dc=intridea, dc=com'], :mail => ['ping@intridea.com'], :givenname => ['Ping'], :sn => ['Yu'],
87
+ :telephonenumber => ['555-555-5555'], :mobile => ['444-444-4444'], :uid => ['ping'], :title => ['dev'], :address =>[ 'k street'],
88
+ :l => ['Washington'], :st => ['DC'], :co => ["U.S.A"], :postofficebox => ['20001'], :wwwhomepage => ['www.intridea.com'],
89
+ :jpegphoto => ['http://www.intridea.com/ping.jpg'], :description => ['omniauth-ldap']})
90
+ post('/auth/ldap/callback', {:username => 'ping', :password => 'password'})
91
+ end
92
+
93
+ it 'should raise MissingCredentialsError' do
94
+ should_not raise_error OmniAuth::Strategies::LDAP::MissingCredentialsError
95
+ end
96
+ it 'should map user info' do
97
+ auth_hash.uid.should == 'cn=ping, dc=intridea, dc=com'
98
+ auth_hash.info.email.should == 'ping@intridea.com'
99
+ auth_hash.info.first_name.should == 'Ping'
100
+ auth_hash.info.last_name.should == 'Yu'
101
+ auth_hash.info.phone.should == '555-555-5555'
102
+ auth_hash.info.mobile.should == '444-444-4444'
103
+ auth_hash.info.nickname.should == 'ping'
104
+ auth_hash.info.title.should == 'dev'
105
+ auth_hash.info.location.should == 'k street, Washington, DC, U.S.A 20001'
106
+ auth_hash.info.url.should == 'www.intridea.com'
107
+ auth_hash.info.image.should == 'http://www.intridea.com/ping.jpg'
108
+ auth_hash.info.description.should == 'omniauth-ldap'
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ describe "OmniAuth::LDAP::Adaptor" do
3
+
4
+ describe 'initialize' do
5
+
6
+ it 'should throw exception when must have field is not set' do
7
+ #[:host, :port, :method, :bind_dn]
8
+ lambda { OmniAuth::LDAP::Adaptor.new({host: "192.168.1.145", method: 'plain'})}.should raise_error(ArgumentError)
9
+ end
10
+ it 'should throw exception when method is not supported' do
11
+ lambda { OmniAuth::LDAP::Adaptor.new({host: "192.168.1.145", method: 'myplain', uid: 'uid', port: 389, base: 'dc=com'})}.should raise_error(OmniAuth::LDAP::Adaptor::ConfigurationError)
12
+ end
13
+
14
+ it 'should setup ldap connection with anonymous' do
15
+ adaptor = OmniAuth::LDAP::Adaptor.new({host: "192.168.1.145", method: 'plain', base: 'dc=intridea, dc=com', port: 389, uid: 'sAMAccountName'})
16
+ adaptor.connection.should_not == nil
17
+ adaptor.connection.host.should == '192.168.1.145'
18
+ adaptor.connection.port.should == 389
19
+ adaptor.connection.base.should == 'dc=intridea, dc=com'
20
+ adaptor.connection.instance_variable_get('@auth').should == {:method => :anonymous, :username => nil, :password => nil}
21
+ end
22
+ it 'should setup ldap connection with simple' do
23
+ adaptor = OmniAuth::LDAP::Adaptor.new({host: "192.168.1.145", method: 'plain', base: 'dc=intridea, dc=com', port: 389, uid: 'sAMAccountName', bind_dn: 'bind_dn', password: 'password'})
24
+ adaptor.connection.should_not == nil
25
+ adaptor.connection.host.should == '192.168.1.145'
26
+ adaptor.connection.port.should == 389
27
+ adaptor.connection.base.should == 'dc=intridea, dc=com'
28
+ adaptor.connection.instance_variable_get('@auth').should == {:method => :simple, :username => 'bind_dn', :password => 'password'}
29
+ end
30
+ it 'should setup ldap connection with sasl-md5' do
31
+ adaptor = OmniAuth::LDAP::Adaptor.new({host: "192.168.1.145", method: 'plain', base: 'dc=intridea, dc=com', port: 389, uid: 'sAMAccountName', try_sasl: true, sasl_mechanisms: ["DIGEST-MD5"], bind_dn: 'bind_dn', password: 'password'})
32
+ adaptor.connection.should_not == nil
33
+ adaptor.connection.host.should == '192.168.1.145'
34
+ adaptor.connection.port.should == 389
35
+ adaptor.connection.base.should == 'dc=intridea, dc=com'
36
+ adaptor.connection.instance_variable_get('@auth')[:method].should == :sasl
37
+ adaptor.connection.instance_variable_get('@auth')[:mechanism].should == 'DIGEST-MD5'
38
+ adaptor.connection.instance_variable_get('@auth')[:initial_credential].should == ''
39
+ adaptor.connection.instance_variable_get('@auth')[:challenge_response].should_not be_nil
40
+ end
41
+ it 'should setup ldap connection with sasl-gss' do
42
+ adaptor = OmniAuth::LDAP::Adaptor.new({host: "192.168.1.145", method: 'plain', base: 'dc=intridea, dc=com', port: 389, uid: 'sAMAccountName', try_sasl: true, sasl_mechanisms: ["GSS-SPNEGO"], bind_dn: 'bind_dn', password: 'password'})
43
+ adaptor.connection.should_not == nil
44
+ adaptor.connection.host.should == '192.168.1.145'
45
+ adaptor.connection.port.should == 389
46
+ adaptor.connection.base.should == 'dc=intridea, dc=com'
47
+ adaptor.connection.instance_variable_get('@auth')[:method].should == :sasl
48
+ adaptor.connection.instance_variable_get('@auth')[:mechanism].should == 'GSS-SPNEGO'
49
+ adaptor.connection.instance_variable_get('@auth')[:initial_credential].should =~ /^NTLMSSP/
50
+ adaptor.connection.instance_variable_get('@auth')[:challenge_response].should_not be_nil
51
+ end
52
+ end
53
+
54
+ describe 'bind_as' do
55
+ let(:args) { {:filter => Net::LDAP::Filter.eq('sAMAccountName', 'username'), :password => 'password', :size => 1} }
56
+ let(:rs) { Struct.new(:dn).new('new dn') }
57
+ it 'should bind simple' do
58
+ adaptor = OmniAuth::LDAP::Adaptor.new({host: "192.168.1.126", method: 'plain', base: 'dc=score, dc=local', port: 389, uid: 'sAMAccountName', bind_dn: 'bind_dn', password: 'password'})
59
+ adaptor.connection.should_receive(:open).and_yield(adaptor.connection)
60
+ adaptor.connection.should_receive(:search).with(args).and_return([rs])
61
+ adaptor.connection.should_receive(:bind).with({:username => 'new dn', :password => args[:password], :method => :simple}).and_return(true)
62
+ adaptor.bind_as(args).should == rs
63
+ end
64
+ it 'should bind sasl' do
65
+ adaptor = OmniAuth::LDAP::Adaptor.new({host: "192.168.1.145", method: 'plain', base: 'dc=intridea, dc=com', port: 389, uid: 'sAMAccountName', try_sasl: true, sasl_mechanisms: ["GSS-SPNEGO"], bind_dn: 'bind_dn', password: 'password'})
66
+ adaptor.connection.should_receive(:open).and_yield(adaptor.connection)
67
+ adaptor.connection.should_receive(:search).with(args).and_return([rs])
68
+ adaptor.connection.should_receive(:bind).and_return(true)
69
+ adaptor.bind_as(args).should == rs
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,12 @@
1
+ $:.unshift File.expand_path('..', __FILE__)
2
+ $:.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'rspec'
4
+ require 'rack/test'
5
+ require 'omniauth'
6
+ require 'omniauth-ldap'
7
+
8
+ RSpec.configure do |config|
9
+ config.include Rack::Test::Methods
10
+ config.extend OmniAuth::Test::StrategyMacros, :type => :strategy
11
+ end
12
+
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gitlab_omniauth-ldap
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ping Yu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: omniauth
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: net-ldap
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.2.2
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.2.2
46
+ - !ruby/object:Gem::Dependency
47
+ name: pyu-ruby-sasl
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.0.3.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.3.1
62
+ - !ruby/object:Gem::Dependency
63
+ name: rubyntlm
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 0.1.1
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.1.1
78
+ description: A LDAP strategy for OmniAuth.
79
+ email:
80
+ - ping@intridea.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - .rspec
87
+ - .travis.yml
88
+ - Gemfile
89
+ - Gemfile.lock
90
+ - Guardfile
91
+ - README.md
92
+ - Rakefile
93
+ - gitlab_omniauth-ldap.gemspec
94
+ - lib/omniauth-ldap.rb
95
+ - lib/omniauth-ldap/adaptor.rb
96
+ - lib/omniauth-ldap/version.rb
97
+ - lib/omniauth/strategies/ldap.rb
98
+ - spec/omniauth-ldap/adaptor_spec.rb
99
+ - spec/omniauth/strategies/ldap_spec.rb
100
+ - spec/spec_helper.rb
101
+ homepage: https://github.com/gitlabhq/omniauth-ldap
102
+ licenses: []
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 1.8.23
122
+ signing_key:
123
+ specification_version: 3
124
+ summary: A LDAP strategy for OmniAuth.
125
+ test_files: []