another-ldap-proxy 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f2e847966bbe4b21b049e7ffb11ad4f1146b6e45c29fdc3d8f976a1595d949ac
4
+ data.tar.gz: b37b3c3ef4bfb8dc085f6f30ce181ed13f6247143c5dfbdaa0905ab4e92702fb
5
+ SHA512:
6
+ metadata.gz: 8675cf5fdb9bc53341f1289f1b088ffce87fdebf3572521fe4757fcbfc001910dac0cb84d934b6be7915042ab61517107b1e163de308f5d7155066cd640d2cbf
7
+ data.tar.gz: a131f32681025bfbd7206e269d0d95eea554f81fb13e7fdbe821ce5a9b7bc98cd4961ab0b9f2b08652f1fea2927e9fc5523fb2060ea514184c4870e57f3febe1
data/.rubocop.yml ADDED
@@ -0,0 +1,36 @@
1
+ require:
2
+ - rubocop-rake
3
+ - rubocop-minitest
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 3.0
7
+ NewCops: enable
8
+
9
+ Gemspec/DevelopmentDependencies:
10
+ Enabled: false
11
+
12
+ Layout/LineLength:
13
+ Max: 120
14
+
15
+ # Metrics/AbcSize:
16
+ # Max: 40
17
+
18
+ Metrics/BlockLength:
19
+ Exclude:
20
+ - another-ldap-proxy.gemspec
21
+ - test/**/*.rb
22
+
23
+ Metrics/ClassLength:
24
+ Exclude:
25
+ - test/**/*.rb
26
+
27
+ Metrics/MethodLength:
28
+ Max: 25
29
+ Exclude:
30
+ - test/**/*.rb
31
+
32
+ # Metrics/ParameterLists:
33
+ # Exclude: []
34
+
35
+ Style/Documentation:
36
+ Enabled: false
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Thomas Tych
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Another::Ldap::Proxy
2
+
3
+ TODO: Delete this and the text below, and describe your gem
4
+
5
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/another/ldap/proxy`. To experiment with that code, run `bin/console` for an interactive prompt.
6
+
7
+ ## Installation
8
+
9
+ TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
10
+
11
+ Install the gem and add to the application's Gemfile by executing:
12
+
13
+ ```bash
14
+ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
15
+ ```
16
+
17
+ If bundler is not being used to manage dependencies, install the gem by executing:
18
+
19
+ ```bash
20
+ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/another-ldap-proxy.
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'minitest/test_task'
5
+
6
+ Minitest::TestTask.create(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.warning = false
10
+ t.test_globs = ['test/**/*_test.rb', 'test/**/test_*.rb']
11
+ end
12
+
13
+ require 'rubocop/rake_task'
14
+
15
+ RuboCop::RakeTask.new
16
+
17
+ require 'bump/tasks'
18
+
19
+ task default: %i[test rubocop]
@@ -0,0 +1,17 @@
1
+ ---
2
+
3
+ port: 1389
4
+ nodelay: yes
5
+ listen: 10
6
+
7
+ root_username: admin
8
+ root_password: admin
9
+
10
+ backend_mode: first
11
+ backends:
12
+ - type: ldap
13
+ url: http://ldap.test.org
14
+ base: dc=base
15
+ auth_method: simple
16
+ username: admin
17
+ password: admin
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'gli'
4
+
5
+ require 'another/ldap/proxy'
6
+
7
+ class Cli
8
+ extend GLI::App
9
+
10
+ program_desc 'Another::Ldap::Proxy CLI'
11
+
12
+ version Another::Ldap::Proxy::VERSION
13
+
14
+ desc 'Start the proxy'
15
+ command :start do |c|
16
+ c.desc 'Configuration file (YAML)'
17
+ c.default_value "./proxy.yml"
18
+ c.arg_name 'proxy.yml'
19
+ c.flag [:c, :config], required: true
20
+
21
+ c.action do |global_options, options, args|
22
+ action_options = global_options.update(options)
23
+
24
+ conf = Another::Ldap::Proxy::Conf.from_file(action_options[:config])
25
+ Another::Ldap::Proxy::Server.run(conf: conf)
26
+ end
27
+ end
28
+
29
+ default_command :start
30
+ end
31
+
32
+ exit Cli.run(ARGV)
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'net/ldap'
5
+
6
+ module Another
7
+ module Ldap
8
+ module Proxy
9
+ module Backend
10
+ class Ldap
11
+ TYPE = 'ldap'
12
+ CONNECT_TIMEOUT = 15
13
+
14
+ attr_reader :url, :base, :auth_method, :username, :password, :type,
15
+ :ca_file, :logger, :parsed_url
16
+
17
+ def initialize(url:, base:, auth_method:, username:, password:, type:, ca_file: nil, logger: nil,
18
+ **unused)
19
+ @url = url
20
+ @base = base
21
+ @auth_method = auth_method
22
+ @username = username
23
+ @password = password
24
+ @type = type
25
+ @ca_file = ca_file
26
+ @logger = logger
27
+ @unused = unused
28
+
29
+ @parsed_url = URI.parse(url)
30
+
31
+ raise "backend type is expected to be #{TYPE} not '#{type}'" unless type == TYPE
32
+ end
33
+
34
+ def new_client(host: self.host, port: self.port, base: self.base, auth: self.auth,
35
+ encryption: self.encryption, connect_timeout: CONNECT_TIMEOUT)
36
+ Net::LDAP.new(
37
+ host: host,
38
+ port: port,
39
+ base: base,
40
+ auth: auth,
41
+ encryption: encryption,
42
+ connect_timeout: connect_timeout
43
+ )
44
+ end
45
+
46
+ def client
47
+ @client ||= new_client
48
+ end
49
+
50
+ def host
51
+ parsed_url.host
52
+ end
53
+
54
+ def port
55
+ parsed_url.port
56
+ end
57
+
58
+ def auth(username: self.username, password: self.password)
59
+ return unless auth_method && username && password
60
+
61
+ { method: auth_method.to_sym,
62
+ username: username,
63
+ password: password }
64
+ end
65
+
66
+ def encryption
67
+ return unless parsed_url.scheme == 'ldaps'
68
+
69
+ { method: :simple_tls,
70
+ tls_options: { ca_file: ca_file } }
71
+ end
72
+
73
+ def bind(_version, dn, password)
74
+ bind_ldap = new_client(auth: auth(username: dn, password: password))
75
+ status = bind_ldap.bind ? true : false
76
+ logger&.info "Ldap#bind : #{dn} => #{status}"
77
+
78
+ status
79
+ end
80
+
81
+ def search(basedn, scope, _deref, filter)
82
+ results = []
83
+ client.search(base: search_base(basedn), scope: scope, filter: filter, return_results: true) do |entry|
84
+ results << entry
85
+ end
86
+ results
87
+ rescue Net::LDAP::Error => e
88
+ logger&.warn "Ldap#search : Error querying LDAP server: #{e.message}"
89
+ []
90
+ end
91
+
92
+ def search_base(basedn)
93
+ return base unless basedn
94
+ return basedn if basedn.include?(base)
95
+
96
+ base
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'backend/ldap'
4
+
5
+ module Another
6
+ module Ldap
7
+ module Proxy
8
+ module Backend
9
+ class << self
10
+ def new_backend(backend_conf, logger: nil)
11
+ backend_type = backend_conf[:type]
12
+ send("new_backend_#{backend_type}", backend_conf, logger: logger)
13
+ end
14
+
15
+ def new_backend_ldap(backend_conf, logger: nil)
16
+ Backend::Ldap.new(**backend_conf, logger: logger)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'yaml'
5
+
6
+ module Another
7
+ module Ldap
8
+ module Proxy
9
+ class Conf
10
+ extend Forwardable
11
+ def_delegators :@conf, :slice, :get, :[]
12
+
13
+ attr_reader :conf
14
+
15
+ def initialize(conf)
16
+ @conf = conf
17
+ end
18
+
19
+ def self.from_file(conf_file)
20
+ raise "Configuration file not found: #{conf_file}" unless File.exist?(conf_file)
21
+
22
+ conf_data = YAML.safe_load_file(conf_file, symbolize_names: true)
23
+ new(conf_data)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Another
4
+ module Ldap
5
+ module Proxy
6
+ module EntryConverter
7
+ NORMALIZED_ATTRIBUTE = {
8
+ 'objectclass' => 'objectClass',
9
+ 'memberof' => 'memberOf'
10
+ }.freeze
11
+
12
+ def self.from_client_to_server(entry)
13
+ dn = entry.dn
14
+ attributes = {}
15
+
16
+ entry.each do |attribute, value|
17
+ next if attribute.to_s == 'dn'
18
+
19
+ attribute = normalize_attribute(attribute)
20
+ attributes[attribute] = value
21
+ end
22
+
23
+ [dn, attributes]
24
+ end
25
+
26
+ def self.normalize_attribute(attribute)
27
+ attribute = attribute.to_s
28
+ NORMALIZED_ATTRIBUTE.fetch(attribute, attribute)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ldap/server'
4
+ require 'net/ldap'
5
+
6
+ module Another
7
+ module Ldap
8
+ module Proxy
9
+ module FilterConverter
10
+ def self.from_server_to_client(filter)
11
+ return filter unless filter.is_a?(Array)
12
+
13
+ operator, *items = filter.compact
14
+ case operator
15
+ when :eq
16
+ Net::LDAP::Filter.eq(items.first, items.last)
17
+ when :ge
18
+ Net::LDAP::Filter.ge(items.first, items.last)
19
+ when :le
20
+ Net::LDAP::Filter.le(items.first, items.last)
21
+ when :present
22
+ Net::LDAP::Filter.pres(items.first)
23
+ when :and
24
+ Net::LDAP::Filter.join(from_server_to_client(items.first),
25
+ from_server_to_client(items.last))
26
+ when :or
27
+ Net::LDAP::Filter.intersect(from_server_to_client(items.first),
28
+ from_server_to_client(items.last))
29
+ when :not
30
+ Net::LDAP::Filter.negate(from_server_to_client(items.first))
31
+ else
32
+ raise "Unsupported server filter operator: #{operator}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'ldap/server'
5
+
6
+ require_relative 'scope_converter'
7
+ require_relative 'filter_converter'
8
+ require_relative 'entry_converter'
9
+
10
+ module Another
11
+ module Ldap
12
+ module Proxy
13
+ class Operation < LDAP::Server::Operation
14
+ PROXY_MODE_FIRST = 'first'
15
+
16
+ attr_reader :logger
17
+
18
+ def initialize(connection, messageID)
19
+ super
20
+
21
+ @proxy_mode = self.class.backend_mode
22
+ @proxy_backends = self.class.backends
23
+ @root_username = self.class.root_username
24
+ @root_password = self.class.root_password
25
+ @logger = self.class.logger
26
+ end
27
+
28
+ def simple_bind(version, dn, password)
29
+ logger&.info "Operation#simple_bind ( #{version}, #{dn}, *** )"
30
+
31
+ return if _validate_root_credentials(dn, password)
32
+
33
+ @proxy_backends.each do |backend|
34
+ return if backend.bind(version, dn, password)
35
+ end
36
+
37
+ logger&.warn "Operation#simple_bind : user #{dn} rejected"
38
+ raise LDAP::ResultError::InvalidCredentials, "user #{dn} rejected"
39
+ end
40
+
41
+ def search(basedn, scope, deref, filter)
42
+ logger&.info "Operation#search ( #{basedn}, #{scope}, #{filter} )"
43
+
44
+ client_scope = Another::Ldap::Proxy::ScopeConverter.from_server_to_client(scope)
45
+ client_filter = Another::Ldap::Proxy::FilterConverter.from_server_to_client(filter)
46
+
47
+ @proxy_backends.each do |backend|
48
+ results = backend.search(basedn, client_scope, deref, client_filter)
49
+
50
+ next if results.empty?
51
+
52
+ results.each do |entry|
53
+ dn, attributes = Another::Ldap::Proxy::EntryConverter.from_client_to_server(entry)
54
+ send_SearchResultEntry(dn, attributes)
55
+ end
56
+
57
+ break if @proxy_mode == PROXY_MODE_FIRST
58
+ end
59
+ end
60
+
61
+ def _validate_root_credentials(username, password)
62
+ @root_username == username && @root_password == password
63
+ end
64
+
65
+ class << self
66
+ attr_reader :backend_mode, :backends, :root_username, :root_password, :logger
67
+
68
+ def new_operation(&block)
69
+ proxy_operation_class = Class.new(self)
70
+ proxy_operation_class.instance_eval(&block) if block_given?
71
+ proxy_operation_class
72
+ end
73
+
74
+ def set_logger(logger)
75
+ @logger = logger
76
+ end
77
+
78
+ def set_root_credentials(root_username, root_password)
79
+ @root_username = root_username
80
+ @root_password = root_password
81
+ end
82
+
83
+ def set_backend_mode(backend_mode)
84
+ @backend_mode = backend_mode
85
+ end
86
+
87
+ def add_backend(backend)
88
+ @backends ||= []
89
+ @backends << backend if backend
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ldap/server'
4
+ require 'net/ldap'
5
+
6
+ module Another
7
+ module Ldap
8
+ module Proxy
9
+ module ScopeConverter
10
+ def self.from_server_to_client(scope)
11
+ case scope
12
+ when LDAP::Server::BaseObject
13
+ Net::LDAP::SearchScope_BaseObject
14
+ when LDAP::Server::SingleLevel
15
+ Net::LDAP::SearchScope_SingleLevel
16
+ when LDAP::Server::WholeSubtree
17
+ Net::LDAP::SearchScope_WholeSubtree
18
+ else
19
+ raise "Unsupported server scope: #{scope}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'ldap/server'
5
+
6
+ module Another
7
+ module Ldap
8
+ module Proxy
9
+ class Server
10
+ SERVER_OPTIONS = %i[port nodelay listen].freeze
11
+
12
+ attr_reader :conf, :logger
13
+
14
+ def initialize(conf:, logger: nil)
15
+ @conf = conf
16
+ @logger = logger || Logger.new($stdout)
17
+ # @logger.level = Logger::DEBUG
18
+ end
19
+
20
+ def server_params
21
+ conf.slice(*SERVER_OPTIONS)
22
+ .update(operation_class_params)
23
+ .update(logger_params)
24
+ end
25
+
26
+ def operation_class
27
+ backend_mode = conf[:backend_mode]
28
+ backends_conf = conf[:backends]
29
+ root_username = conf[:root_username]
30
+ root_password = conf[:root_password]
31
+ logger = self.logger
32
+ Another::Ldap::Proxy::Operation.new_operation do
33
+ set_logger(logger)
34
+ set_root_credentials(root_username,
35
+ root_password)
36
+ set_backend_mode(backend_mode)
37
+ backends_conf.each do |backend_conf|
38
+ add_backend(Another::Ldap::Proxy::Backend.new_backend(backend_conf, logger: logger))
39
+ end
40
+ end
41
+ end
42
+
43
+ def operation_class_params
44
+ { operation_class: operation_class }
45
+ end
46
+
47
+ def logger_params
48
+ { logger: logger }
49
+ end
50
+
51
+ def run
52
+ @s ||= LDAP::Server.new(
53
+ **server_params
54
+ )
55
+
56
+ @s.run_tcpserver
57
+ @s.join
58
+ end
59
+
60
+ def self.run(conf:)
61
+ new(conf: conf).run
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Another
4
+ module Ldap
5
+ module Proxy
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'proxy/version'
4
+ require_relative 'proxy/server'
5
+ require_relative 'proxy/conf'
6
+ require_relative 'proxy/operation'
7
+ require_relative 'proxy/backend'
8
+
9
+ module Another
10
+ module Ldap
11
+ module Proxy
12
+ class Error < StandardError; end
13
+ # Your code goes here...
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ module Another
2
+ module Ldap
3
+ module Proxy
4
+ VERSION: String
5
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
6
+ end
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,258 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: another-ldap-proxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Thomas Tych
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-11-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gli
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.22'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.22'
27
+ - !ruby/object:Gem::Dependency
28
+ name: net-ldap
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.19.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.19.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-ldapserver
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.7.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.7.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: bump
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.10.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.10.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 2.5.6
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 2.5.6
83
+ - !ruby/object:Gem::Dependency
84
+ name: byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '11.1'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 11.1.3
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '11.1'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 11.1.3
103
+ - !ruby/object:Gem::Dependency
104
+ name: minitest
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '5.16'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '5.16'
117
+ - !ruby/object:Gem::Dependency
118
+ name: rake
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '13.0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '13.0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: reek
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '6.1'
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: 6.1.4
141
+ type: :development
142
+ prerelease: false
143
+ version_requirements: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - "~>"
146
+ - !ruby/object:Gem::Version
147
+ version: '6.1'
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: 6.1.4
151
+ - !ruby/object:Gem::Dependency
152
+ name: rubocop
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: '1.56'
158
+ type: :development
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: '1.56'
165
+ - !ruby/object:Gem::Dependency
166
+ name: rubocop-minitest
167
+ requirement: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - "~>"
170
+ - !ruby/object:Gem::Version
171
+ version: 0.36.0
172
+ type: :development
173
+ prerelease: false
174
+ version_requirements: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - "~>"
177
+ - !ruby/object:Gem::Version
178
+ version: 0.36.0
179
+ - !ruby/object:Gem::Dependency
180
+ name: rubocop-rake
181
+ requirement: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - "~>"
184
+ - !ruby/object:Gem::Version
185
+ version: 0.6.0
186
+ type: :development
187
+ prerelease: false
188
+ version_requirements: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - "~>"
191
+ - !ruby/object:Gem::Version
192
+ version: 0.6.0
193
+ - !ruby/object:Gem::Dependency
194
+ name: simplecov
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: 0.22.0
200
+ type: :development
201
+ prerelease: false
202
+ version_requirements: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - "~>"
205
+ - !ruby/object:Gem::Version
206
+ version: 0.22.0
207
+ description: Another Ldap Proxy implementation for search query.
208
+ email:
209
+ - thomas.tych@gmail.com
210
+ executables:
211
+ - another-ldap-proxy
212
+ extensions: []
213
+ extra_rdoc_files: []
214
+ files:
215
+ - ".rubocop.yml"
216
+ - LICENSE.txt
217
+ - README.md
218
+ - Rakefile
219
+ - examples/proxy.yml
220
+ - exe/another-ldap-proxy
221
+ - lib/another/ldap/proxy.rb
222
+ - lib/another/ldap/proxy/backend.rb
223
+ - lib/another/ldap/proxy/backend/ldap.rb
224
+ - lib/another/ldap/proxy/conf.rb
225
+ - lib/another/ldap/proxy/entry_converter.rb
226
+ - lib/another/ldap/proxy/filter_converter.rb
227
+ - lib/another/ldap/proxy/operation.rb
228
+ - lib/another/ldap/proxy/scope_converter.rb
229
+ - lib/another/ldap/proxy/server.rb
230
+ - lib/another/ldap/proxy/version.rb
231
+ - sig/another/ldap/proxy.rbs
232
+ homepage: https://gitlab.com/ttych/another-ldap-proxy.rb
233
+ licenses:
234
+ - MIT
235
+ metadata:
236
+ homepage_uri: https://gitlab.com/ttych/another-ldap-proxy.rb
237
+ source_code_uri: https://gitlab.com/ttych/another-ldap-proxy.rb.git
238
+ rubygems_mfa_required: 'true'
239
+ post_install_message:
240
+ rdoc_options: []
241
+ require_paths:
242
+ - lib
243
+ required_ruby_version: !ruby/object:Gem::Requirement
244
+ requirements:
245
+ - - ">="
246
+ - !ruby/object:Gem::Version
247
+ version: 3.0.0
248
+ required_rubygems_version: !ruby/object:Gem::Requirement
249
+ requirements:
250
+ - - ">="
251
+ - !ruby/object:Gem::Version
252
+ version: '0'
253
+ requirements: []
254
+ rubygems_version: 3.5.22
255
+ signing_key:
256
+ specification_version: 4
257
+ summary: Another Ldap Proxy
258
+ test_files: []