pg-ldap-sync-0.3.0/0000755000004100000410000000000014173767325014057 5ustar www-datawww-datapg-ldap-sync-0.3.0/.travis.yml0000644000004100000410000000130114173767325016163 0ustar www-datawww-datasudo: required dist: focal language: ruby rvm: - "2.4.0" - ruby-head env: - "PGVERSION=14" - "PGVERSION=9.6" before_install: - gem install bundler --no-doc --conservative - bundle install # Download and install postgresql version to test against in /opt (for non-cross compile only) - echo "deb http://apt.postgresql.org/pub/repos/apt/ ${TRAVIS_DIST}-pgdg main $PGVERSION" | sudo tee -a /etc/apt/sources.list.d/pgdg.list - wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - - sudo apt -y update - sudo apt -y --allow-downgrades install postgresql-$PGVERSION libpq-dev - export PATH=/usr/lib/postgresql/$PGVERSION/bin:$PATH script: rake test pg-ldap-sync-0.3.0/README.md0000644000004100000410000000547114173767325015345 0ustar www-datawww-data[![Build Status](https://app.travis-ci.com/larskanis/pg-ldap-sync.svg?branch=master)](https://app.travis-ci.com/larskanis/pg-ldap-sync) [![Build status](https://ci.appveyor.com/api/projects/status/09xn9q5p64jbxtka/branch/master?svg=true)](https://ci.appveyor.com/project/larskanis/pg-ldap-sync/branch/master) # Use LDAP permissions in PostgreSQL * http://github.com/larskanis/pg-ldap-sync ## DESCRIPTION: LDAP is often used for a centralized user and role management in an enterprise environment. PostgreSQL offers different authentication methods, like LDAP, SSPI, GSSAPI or SSL. However, for any method the user must already exist in the database, before the authentication can be used. There is currently no direct authorization of database users on LDAP. So roles and memberships has to be administered twice. This program helps to solve the issue by synchronizing users, groups and their memberships from LDAP to PostgreSQL. Access to LDAP is used read-only. `pg_ldap_sync` issues proper CREATE ROLE, DROP ROLE, GRANT and REVOKE commands to synchronize users and groups. It is meant to be started as a cron job. ## FEATURES: * Configurable per YAML config file * Can use Active Directory as LDAP-Server * Nested groups/roles supported * Set scope of considered users/groups on LDAP and PG side * Test mode which doesn't do any changes to the DBMS * Both LDAP and PG connections can be secured by SSL/TLS ## REQUIREMENTS: * Ruby-2.0+, JRuby-1.2+ * LDAP-v3 server * PostgreSQL-server v9.0+ ## INSTALL: Install Ruby: * on Windows: http://rubyinstaller.org * on Debian/Ubuntu: `apt-get install ruby libpq-dev` Install pg-ldap-sync and required dependencies: ```sh gem install pg-ldap-sync ``` ### Install from Git: ```sh git clone https://github.com/larskanis/pg-ldap-sync.git cd pg-ldap-sync gem install bundler bundle install bundle exec rake install ``` ## USAGE: Create a config file based on [config/sample-config.yaml](https://github.com/larskanis/pg-ldap-sync/blob/master/config/sample-config.yaml) or even better [config/sample-config2.yaml](https://github.com/larskanis/pg-ldap-sync/blob/master/config/sample-config2.yaml) Run in test-mode: ```sh pg_ldap_sync -c my_config.yaml -vv -t ``` Run in modify-mode: ```sh pg_ldap_sync -c my_config.yaml -vv ``` ## TEST: There is a small test suite in the `test` directory that runs against an internal LDAP server and a PostgreSQL server. Ensure `pg_ctl`, `initdb` and `psql` commands are in the `PATH` like so: ```sh cd pg-ldap-sync bundle install PATH=$PATH:/usr/lib/postgresql/10/bin/ bundle exec rake test ``` ## ISSUES: * There is currently no way to set certain user attributes in PG based on individual attributes in LDAP (expiration date etc.) ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). pg-ldap-sync-0.3.0/data.tar.gz.sig0000444000004100000410000000040014173767325016670 0ustar www-datawww-dataKeu&70*)RN&'rÉ4vca>j-kR$ͱN`e2Ja7($"y2eob#ۤx3ll]?sRW$f'X4i"ȾQ+0ю3F]ku! a*pg-ldap-sync-0.3.0/.gitignore0000644000004100000410000000013514173767325016046 0ustar www-datawww-data/.bundle/ /.yardoc /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ /temp/ Gemfile.lock pg-ldap-sync-0.3.0/pg-ldap-sync.gemspec0000644000004100000410000000242214173767325017722 0ustar www-datawww-datalib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require "pg_ldap_sync/version" Gem::Specification.new do |spec| spec.name = "pg-ldap-sync" spec.version = PgLdapSync::VERSION spec.authors = ["Lars Kanis"] spec.email = ["lars@greiz-reinsdorf.de"] spec.summary = %q{Use LDAP permissions in PostgreSQL} spec.homepage = "https://github.com/larskanis/pg-ldap-sync" spec.license = "MIT" spec.files = `git ls-files -z`.split("\x0").reject do |f| f.match(%r{^(test|spec|features)/}) end spec.bindir = "exe" spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] spec.rdoc_options = %w[--main README.md --charset=UTF-8] spec.required_ruby_version = ">= 2.4" spec.add_runtime_dependency "net-ldap", "~> 0.16" spec.add_runtime_dependency "kwalify", "~> 0.7" spec.add_runtime_dependency "pg", ">= 0.14", "< 2.0" spec.add_development_dependency "ruby-ldapserver", "~> 0.3" spec.add_development_dependency "minitest", "~> 5.0" spec.add_development_dependency "bundler", ">= 1.16", "< 3.0" spec.add_development_dependency "rake", "~> 13.0" spec.add_development_dependency "minitest-hooks", "~> 1.4" end pg-ldap-sync-0.3.0/.autotest0000644000004100000410000000074014173767325015731 0ustar www-datawww-data# -*- ruby -*- require 'autotest/restart' # Autotest.add_hook :initialize do |at| # at.extra_files << "../some/external/dependency.rb" # # at.libs << ":../some/external" # # at.add_exception 'vendor' # # at.add_mapping(/dependency.rb/) do |f, _| # at.files_matching(/test_.*rb$/) # end # # %w(TestA TestB).each do |klass| # at.extra_class_map[klass] = "test/test_misc.rb" # end # end # Autotest.add_hook :run_command do |at| # system "rake build" # end pg-ldap-sync-0.3.0/Rakefile0000644000004100000410000000032214173767325015521 0ustar www-datawww-data# -*- ruby -*- require "bundler/gem_tasks" require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList["test/**/test_*.rb"] end task :gem => :build pg-ldap-sync-0.3.0/lib/0000755000004100000410000000000014173767325014625 5ustar www-datawww-datapg-ldap-sync-0.3.0/lib/pg_ldap_sync/0000755000004100000410000000000014173767325017267 5ustar www-datawww-datapg-ldap-sync-0.3.0/lib/pg_ldap_sync/version.rb0000644000004100000410000000005214173767325021276 0ustar www-datawww-datamodule PgLdapSync VERSION = "0.3.0" end pg-ldap-sync-0.3.0/lib/pg_ldap_sync/application.rb0000644000004100000410000002620714173767325022126 0ustar www-datawww-data#!/usr/bin/env ruby require 'net/ldap' require 'optparse' require 'yaml' require 'kwalify' require 'pg' require "pg_ldap_sync/logger" module PgLdapSync class Application attr_accessor :config_fname attr_accessor :log attr_accessor :test def string_to_symbol(hash) if hash.kind_of?(Hash) return hash.inject({}) do |h, v| raise "expected String instead of #{h.inspect}" unless v[0].kind_of?(String) h[v[0].intern] = string_to_symbol(v[1]) h end else return hash end end def validate_config(config, schema, fname) schema = YAML.load_file(schema) validator = Kwalify::Validator.new(schema) errors = validator.validate(config) if errors && !errors.empty? errors.each do |err| log.fatal "error in #{fname}: [#{err.path}] #{err.message}" end raise InvalidConfig, 78 # EX_CONFIG end end def read_config_file(fname) raise "Config file #{fname.inspect} does not exist" unless File.exist?(fname) config = YAML.load(File.read(fname)) schema_fname = File.join(File.dirname(__FILE__), '../../config/schema.yaml') validate_config(config, schema_fname, fname) @config = string_to_symbol(config) end LdapRole = Struct.new :name, :dn, :member_dns def search_ldap_users ldap_user_conf = @config[:ldap_users] users = [] res = @ldap.search(:base => ldap_user_conf[:base], :filter => ldap_user_conf[:filter]) do |entry| name = entry[ldap_user_conf[:name_attribute]].first unless name log.warn "user attribute #{ldap_user_conf[:name_attribute].inspect} not defined for #{entry.dn}" next end log.info "found user-dn: #{entry.dn}" names = if ldap_user_conf[:bothcase_name] [name, name.downcase].uniq elsif ldap_user_conf[:lowercase_name] [name.downcase] else [name] end names.each do |n| users << LdapRole.new(n, entry.dn) end entry.each do |attribute, values| log.debug " #{attribute}:" values.each do |value| log.debug " --->#{value.inspect}" end end end raise LdapError, "LDAP: #{@ldap.get_operation_result.message}" unless res return users end def search_ldap_groups ldap_group_conf = @config[:ldap_groups] groups = [] res = @ldap.search(:base => ldap_group_conf[:base], :filter => ldap_group_conf[:filter]) do |entry| name = entry[ldap_group_conf[:name_attribute]].first unless name log.warn "user attribute #{ldap_group_conf[:name_attribute].inspect} not defined for #{entry.dn}" next end log.info "found group-dn: #{entry.dn}" names = if ldap_group_conf[:bothcase_name] [name, name.downcase].uniq elsif ldap_group_conf[:lowercase_name] [name.downcase] else [name] end names.each do |n| groups << LdapRole.new(n, entry.dn, entry[ldap_group_conf[:member_attribute]]) end entry.each do |attribute, values| log.debug " #{attribute}:" values.each do |value| log.debug " --->#{value.inspect}" end end end raise LdapError, "LDAP: #{@ldap.get_operation_result.message}" unless res return groups end PgRole = Struct.new :name, :member_names # List of default roles taken from https://www.postgresql.org/docs/current/predefined-roles.html PG_BUILTIN_ROLES = %w[ pg_read_all_data pg_write_all_data pg_read_all_settings pg_read_all_stats pg_stat_scan_tables pg_monitor pg_database_owner pg_signal_backend pg_read_server_files pg_write_server_files pg_execute_server_program ] def search_pg_users pg_users_conf = @config[:pg_users] users = [] res = pg_exec "SELECT rolname FROM pg_roles WHERE #{pg_users_conf[:filter]}" res.each do |tuple| user = PgRole.new tuple[0] next if PG_BUILTIN_ROLES.include?(user.name) log.info{ "found pg-user: #{user.name.inspect}"} users << user end return users end def search_pg_groups pg_groups_conf = @config[:pg_groups] groups = [] res = pg_exec "SELECT rolname, oid FROM pg_roles WHERE #{pg_groups_conf[:filter]}" res.each do |tuple| res2 = pg_exec "SELECT pr.rolname FROM pg_auth_members pam JOIN pg_roles pr ON pr.oid=pam.member WHERE pam.roleid=#{@pgconn.escape_string(tuple[1])}" member_names = res2.map{|row| row[0] } group = PgRole.new tuple[0], member_names next if PG_BUILTIN_ROLES.include?(group.name) log.info{ "found pg-group: #{group.name.inspect} with members: #{member_names.inspect}"} groups << group end return groups end def uniq_names(list) names = {} new_list = list.select do |entry| name = entry.name if names[name] log.warn{ "duplicated group/user #{name.inspect} (#{entry.inspect})" } next false else names[name] = true next true end end return new_list end MatchedRole = Struct.new :ldap, :pg, :name, :state, :type def match_roles(ldaps, pgs, type) ldap_by_name = ldaps.inject({}){|h,u| h[u.name] = u; h } pg_by_name = pgs.inject({}){|h,u| h[u.name] = u; h } roles = [] ldaps.each do |ld| pg = pg_by_name[ld.name] role = MatchedRole.new ld, pg, ld.name roles << role end pgs.each do |pg| ld = ldap_by_name[pg.name] next if ld role = MatchedRole.new ld, pg, pg.name roles << role end roles.each do |r| r.state = case when r.ldap && !r.pg then :create when !r.ldap && r.pg then :drop when r.pg && r.ldap then :keep else raise "invalid user #{r.inspect}" end r.type = type end log.info do roles.each do |role| log.debug{ "#{role.state} #{role.type}: #{role.name}" } end "#{type} stat: create: #{roles.count{|r| r.state==:create }} drop: #{roles.count{|r| r.state==:drop }} keep: #{roles.count{|r| r.state==:keep }}" end return roles end def try_sql(text) begin @pgconn.exec "SAVEPOINT try_sql;" @pgconn.exec text rescue PG::Error => err @pgconn.exec "ROLLBACK TO try_sql;" log.error{ "#{err} (#{err.class})" } end end def pg_exec_modify(sql) log.info{ "SQL: #{sql}" } unless self.test try_sql sql end end def pg_exec(sql) res = @pgconn.exec sql (0...res.num_tuples).map{|t| (0...res.num_fields).map{|i| res.getvalue(t, i) } } end def create_pg_role(role) pg_conf = @config[role.type==:user ? :pg_users : :pg_groups] pg_exec_modify "CREATE ROLE \"#{role.name}\" #{pg_conf[:create_options]}" end def drop_pg_role(role) pg_exec_modify "DROP ROLE \"#{role.name}\"" end def sync_roles_to_pg(roles, for_state) roles.sort{|a,b| a.name<=>b.name }.each do |role| create_pg_role(role) if role.state==:create && for_state==:create drop_pg_role(role) if role.state==:drop && for_state==:drop end end MatchedMembership = Struct.new :role_name, :has_member, :state def match_memberships(ldap_roles, pg_roles) hash_of_arrays = Hash.new { |h, k| h[k] = [] } ldap_by_dn = ldap_roles.inject(hash_of_arrays){|h,r| h[r.dn] << r; h } ldap_by_m2m = ldap_roles.inject([]) do |a,r| next a unless r.member_dns a + r.member_dns.flat_map do |dn| has_members = ldap_by_dn[dn] log.warn{"ldap member with dn #{dn} is unknown"} if has_members.empty? has_members.map do |has_member| [r.name, has_member.name] end end end hash_of_arrays = Hash.new { |h, k| h[k] = [] } pg_by_name = pg_roles.inject(hash_of_arrays){|h,r| h[r.name] << r; h } pg_by_m2m = pg_roles.inject([]) do |a,r| next a unless r.member_names a + r.member_names.flat_map do |name| has_members = pg_by_name[name] log.warn{"pg member with name #{name} is unknown"} if has_members.empty? has_members.map do |has_member| [r.name, has_member.name] end end end memberships = (ldap_by_m2m & pg_by_m2m).map{|r,mo| MatchedMembership.new r, mo, :keep } memberships += (ldap_by_m2m - pg_by_m2m).map{|r,mo| MatchedMembership.new r, mo, :grant } memberships += (pg_by_m2m - ldap_by_m2m).map{|r,mo| MatchedMembership.new r, mo, :revoke } log.info do memberships.each do |membership| log.debug{ "#{membership.state} #{membership.role_name} to #{membership.has_member}" } end "membership stat: grant: #{memberships.count{|u| u.state==:grant }} revoke: #{memberships.count{|u| u.state==:revoke }} keep: #{memberships.count{|u| u.state==:keep }}" end return memberships end def grant_membership(role_name, add_members) pg_conf = @config[:pg_groups] add_members_escaped = add_members.map{|m| "\"#{m}\"" }.join(",") pg_exec_modify "GRANT \"#{role_name}\" TO #{add_members_escaped} #{pg_conf[:grant_options]}" end def revoke_membership(role_name, rm_members) rm_members_escaped = rm_members.map{|m| "\"#{m}\"" }.join(",") pg_exec_modify "REVOKE \"#{role_name}\" FROM #{rm_members_escaped}" end def sync_membership_to_pg(memberships, for_state) grants = {} memberships.select{|ms| ms.state==for_state }.each do |ms| grants[ms.role_name] ||= [] grants[ms.role_name] << ms.has_member end grants.each do |role_name, members| grant_membership(role_name, members) if for_state==:grant revoke_membership(role_name, members) if for_state==:revoke end end def start! read_config_file(@config_fname) # gather LDAP users and groups @ldap = Net::LDAP.new @config[:ldap_connection] ldap_users = uniq_names search_ldap_users ldap_groups = uniq_names search_ldap_groups # gather PGs users and groups @pgconn = PG.connect @config[:pg_connection] begin @pgconn.transaction do pg_users = uniq_names search_pg_users pg_groups = uniq_names search_pg_groups # compare LDAP to PG users and groups mroles = match_roles(ldap_users, pg_users, :user) mroles += match_roles(ldap_groups, pg_groups, :group) # compare LDAP to PG memberships mmemberships = match_memberships(ldap_users+ldap_groups, pg_users+pg_groups) # drop/revoke roles/memberships first sync_membership_to_pg(mmemberships, :revoke) sync_roles_to_pg(mroles, :drop) # create/grant roles/memberships sync_roles_to_pg(mroles, :create) sync_membership_to_pg(mmemberships, :grant) end ensure @pgconn.close end # Determine exitcode if log.had_errors? raise ErrorExit, 1 end end def self.run(argv) s = self.new s.config_fname = '/etc/pg_ldap_sync.yaml' s.log = Logger.new($stdout, @error_counters) s.log.level = Logger::ERROR OptionParser.new do |opts| opts.version = VERSION opts.banner = "Usage: #{$0} [options]" opts.on("-v", "--[no-]verbose", "Increase verbose level"){|v| s.log.level += v ? -1 : 1 } opts.on("-c", "--config FILE", "Config file [#{s.config_fname}]", &s.method(:config_fname=)) opts.on("-t", "--[no-]test", "Don't do any change in the database", &s.method(:test=)) opts.parse!(argv) end s.start! end end end pg-ldap-sync-0.3.0/lib/pg_ldap_sync/logger.rb0000644000004100000410000000063514173767325021077 0ustar www-datawww-datarequire 'logger' module PgLdapSync class Logger < ::Logger def initialize(io, counters) super(io) @counters = {} end def add(severity, *args) @counters[severity] ||= 0 @counters[severity] += 1 super end def had_logged?(severity) @counters[severity] && @counters[severity] > 0 end def had_errors? had_logged?(Logger::FATAL) || had_logged?(Logger::ERROR) end end end pg-ldap-sync-0.3.0/lib/pg_ldap_sync.rb0000644000004100000410000000054314173767325017616 0ustar www-datawww-datarequire "pg_ldap_sync/application" require "pg_ldap_sync/version" module PgLdapSync class LdapError < RuntimeError end class ApplicationExit < RuntimeError attr_reader :exitcode def initialize(exitcode) @exitcode = exitcode end end class InvalidConfig < ApplicationExit end class ErrorExit < ApplicationExit end end pg-ldap-sync-0.3.0/config/0000755000004100000410000000000014173767325015324 5ustar www-datawww-datapg-ldap-sync-0.3.0/config/sample-config.yaml0000644000004100000410000000353414173767325020741 0ustar www-datawww-data# With this sample config the distinction between PG groups and users is # done by the LOGIN/NOLOGIN attribute. Any non-superuser account # is considered as LDAP-synchronized. # Connection parameters to LDAP server # see also: http://net-ldap.rubyforge.org/Net/LDAP.html#method-c-new ldap_connection: host: localhost port: 389 auth: method: :simple username: CN=username,OU=!Serviceaccounts,OU=company,DC=company,DC=de password: secret # Search parameters for LDAP users which should be synchronized ldap_users: base: OU=company,OU=company,DC=company,DC=de # LDAP filter (according to RFC 2254) # defines to users in LDAP to be synchronized filter: (&(objectClass=person)(objectClass=organizationalPerson)(givenName=*)(sn=*)) # this attribute is used as PG role name name_attribute: sAMAccountName # Search parameters for LDAP groups which should be synchronized ldap_groups: base: OU=company,OU=company,DC=company,DC=de filter: (|(cn=group1)(cn=group2)(cn=group3)) # this attribute is used as PG role name name_attribute: cn # this attribute must reference to all member DN's of the given group member_attribute: member # Connection parameters to PostgreSQL server # see also: http://rubydoc.info/gems/pg/PG/Connection#initialize-instance_method pg_connection: host: dbname: postgres user: db-username password: pg_users: # Filter for identifying LDAP generated users in the database. # It's the WHERE-condition to "SELECT rolname, oid FROM pg_roles" filter: rolcanlogin AND NOT rolsuper # Options for CREATE RULE statements create_options: LOGIN pg_groups: # Filter for identifying LDAP generated groups in the database. # It's the WHERE-condition to "SELECT rolname, oid FROM pg_roles" filter: NOT rolcanlogin AND NOT rolsuper # Options for CREATE RULE statements create_options: NOLOGIN grant_options: pg-ldap-sync-0.3.0/config/schema.yaml0000644000004100000410000000243214173767325017451 0ustar www-datawww-datatype: map mapping: "ldap_connection": type: any required: yes "ldap_users": type: map required: yes mapping: "base": type: str required: yes "filter": type: str required: yes "name_attribute": type: str required: yes "lowercase_name": type: bool required: no "bothcase_name": type: bool required: no "ldap_groups": type: map required: yes mapping: "base": type: str required: yes "filter": type: str required: yes "name_attribute": type: str required: yes "lowercase_name": type: bool required: no "bothcase_name": type: bool required: no "member_attribute": type: str required: yes "pg_connection": type: any required: yes "pg_users": type: map required: yes mapping: "filter": type: str required: yes "create_options": type: str "pg_groups": type: map required: yes mapping: "filter": type: str required: yes "create_options": type: str "grant_options": type: str pg-ldap-sync-0.3.0/config/sample-config2.yaml0000644000004100000410000000455714173767325021031 0ustar www-datawww-data# With this sample config the distinction between LDAP-synchronized # groups/users from is done by the membership to ldap_user and # ldap_group. These two roles has to be defined manally before # pg_ldap_sync can run. # Connection parameters to LDAP server # see also: http://net-ldap.rubyforge.org/Net/LDAP.html#method-c-new ldap_connection: host: ldapserver port: 636 auth: method: :simple username: CN=username,OU=!Serviceaccounts,OU=company,DC=company,DC=de password: secret encryption: method: :simple_tls # Search parameters for LDAP users which should be synchronized ldap_users: base: OU=company,DC=company,DC=prod # LDAP filter (according to RFC 2254) # defines to users in LDAP to be synchronized filter: (&(objectClass=person)(objectClass=organizationalPerson)(givenName=*)(sn=*)(sAMAccountName=*)) # this attribute is used as PG role name name_attribute: sAMAccountName # lowercase name for use as PG role name lowercase_name: true # Add lowercase name *and* original name for use as PG role names (useful for migrating between case types) bothcase_name: false # Search parameters for LDAP groups which should be synchronized ldap_groups: base: OU=company,DC=company,DC=prod filter: (cn=company.*) # this attribute is used as PG role name name_attribute: cn # lowercase name for use as PG role name lowercase_name: false # this attribute must reference to all member DN's of the given group member_attribute: member # Connection parameters to PostgreSQL server # see also: http://rubydoc.info/gems/pg/PG/Connection#initialize-instance_method pg_connection: host: dbname: postgres user: password: pg_users: # Filter for identifying LDAP generated users in the database. # It's the WHERE-condition to "SELECT rolname, oid FROM pg_roles" filter: oid IN (SELECT pam.member FROM pg_auth_members pam JOIN pg_roles pr ON pr.oid=pam.roleid WHERE pr.rolname='ldap_users') # Options for CREATE RULE statements create_options: LOGIN IN ROLE ldap_users pg_groups: # Filter for identifying LDAP generated groups in the database. # It's the WHERE-condition to "SELECT rolname, oid FROM pg_roles" filter: oid IN (SELECT pam.member FROM pg_auth_members pam JOIN pg_roles pr ON pr.oid=pam.roleid WHERE pr.rolname='ldap_groups') # Options for CREATE RULE statements create_options: NOLOGIN IN ROLE ldap_groups grant_options: pg-ldap-sync-0.3.0/Gemfile0000644000004100000410000000014114173767325015346 0ustar www-datawww-datasource "https://rubygems.org" # Specify your gem's dependencies in pg_ldap_sync.gemspec gemspec pg-ldap-sync-0.3.0/appveyor.yml0000644000004100000410000000111614173767325016446 0ustar www-datawww-dataimage: Visual Studio 2019 init: - set PATH=C:/Ruby%ruby_version%/bin;c:/Program Files/Git/cmd;c:/Windows/system32;C:/Windows/System32/WindowsPowerShell/v1.0 - set RUBYOPT=--verbose install: - ver - ruby --version - gem --version - gem install bundler --no-doc --conservative - bundle install build_script: - set PATH=C:/Program Files/PostgreSQL/%PGVER%/bin;%PATH% - md temp - icacls temp /grant Everyone:(OI)(CI)F /T test_script: - bundle exec rake test environment: matrix: - ruby_version: "27-x64" PGVER: 13 - ruby_version: "24" PGVER: 10 pg-ldap-sync-0.3.0/Manifest.txt0000644000004100000410000000045614173767325016373 0ustar www-datawww-data.autotest History.txt Manifest.txt README.rdoc Rakefile bin/pg_ldap_sync config/sample-config.yaml config/sample-config2.yaml config/schema.yaml lib/pg_ldap_sync.rb lib/pg_ldap_sync/application.rb test/fixtures/config-ldapdb.yaml test/fixtures/ldapdb.yaml test/ldap_server.rb test/test_pg_ldap_sync.rb pg-ldap-sync-0.3.0/exe/0000755000004100000410000000000014173767325014640 5ustar www-datawww-datapg-ldap-sync-0.3.0/exe/pg_ldap_sync0000755000004100000410000000022714173767325017231 0ustar www-datawww-data#!/usr/bin/env ruby require 'pg_ldap_sync' begin PgLdapSync::Application.run(ARGV) rescue PgLdapSync::ApplicationExit => ex exit ex.exitcode end pg-ldap-sync-0.3.0/LICENSE.txt0000644000004100000410000000206514173767325015705 0ustar www-datawww-dataThe MIT License (MIT) Copyright (c) 2018 Lars Kanis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.