amp4e_ldap_tool 0.0.3

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e64128d5ab79fad912da68f5e31967613d469498
4
+ data.tar.gz: 827d8801707fc45dbf5b2d2a9b27eec7a10cfe5f
5
+ SHA512:
6
+ metadata.gz: 8c09590f6d6da7b58648168abc5450d0fb2e8a0845e957a2acfd66483035530c91ec263504f9c09019671a162701dab79ac1ddcc02e049a381e8d6b0c5cb8e1a
7
+ data.tar.gz: 4c151efff958954308be12402473c4df0cacdf4a9ad768964a91b60d4975bbbc1bd30e9373ebfb44a112aed2e3c9d0500f72fc44463297da7395bd9a334aeffc
@@ -0,0 +1,52 @@
1
+ *.gem
2
+ *.rbc
3
+ *.swp
4
+ *.swo
5
+ /.config
6
+ /coverage/
7
+ /InstalledFiles
8
+ /pkg/
9
+ /spec/reports/
10
+ /spec/examples.txt
11
+ /test/tmp/
12
+ /test/version_tmp/
13
+ /tmp/
14
+
15
+ # Used by dotenv library to load environment variables.
16
+ # .env
17
+
18
+ ## Specific to RubyMotion:
19
+ .dat*
20
+ .repl_history
21
+ build/
22
+ *.bridgesupport
23
+ build-iPhoneOS/
24
+ build-iPhoneSimulator/
25
+
26
+ ## Specific to RubyMotion (use of CocoaPods):
27
+ #
28
+ # We recommend against adding the Pods directory to your .gitignore. However
29
+ # you should judge for yourself, the pros and cons are mentioned at:
30
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
31
+ #
32
+ # vendor/Pods/
33
+
34
+ ## Documentation cache and generated files:
35
+ /.yardoc/
36
+ /_yardoc/
37
+ /doc/
38
+ /rdoc/
39
+
40
+ ## Environment normalization:
41
+ /.bundle/
42
+ /vendor/bundle
43
+ /lib/bundler/man/
44
+
45
+ # for a library or gem, you might want to ignore these files since the code is
46
+ # intended to run in multiple environments; otherwise, check them in:
47
+ Gemfile.lock
48
+ # .ruby-version
49
+ # .ruby-gemset
50
+
51
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
52
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.4
5
+ before_install: gem install bundler -v 1.12.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in amp4e_ldap_tool.gemspec
4
+ gemspec
@@ -0,0 +1,95 @@
1
+ # amp4e\_ldap\_tool
2
+ Ruby command line script to reconcile computers and groups on Cisco's AMP for Endpoints web portal with local LDAP servers.
3
+
4
+ `gem install amp4e_ldap_tool`
5
+
6
+ ## Commands
7
+ ### AMP
8
+ `amp4e_ldap_tool amp`
9
+
10
+ It makes an HTTP request to the AMP for Endpoints web portal. We must provide flags to tell amp what we want to receive:
11
+
12
+ - `-c` gets a list of Computers in the AMP system.
13
+ - `-g` gets a list of Groups as AMP sees them
14
+ - `-p` gets a list of policies
15
+ - `-t` provides any of the above options with formatted output.
16
+
17
+ ### LDAP
18
+ `amp4e_ldap_tool`
19
+
20
+ It retrieves information from the LDAP server, using credentials provided in your config file. It also requires flags to tell it what to get from the server:
21
+
22
+ - `-c` gets computer names
23
+ - `-g` gets computer group names
24
+ - `-d` gets the fully distinguished name (LDAP)
25
+ - `-t` provides any of the above options with formatted output.
26
+
27
+
28
+ ### Make\_changes
29
+ The command `make_changes` is the workhorse. Calling it on its own:
30
+
31
+ ```
32
+ amp4e_ldap_tool make_changes
33
+ ```
34
+
35
+ Displays the _dry run_, a list of changes that will be changed shown in aggregate. These changes will be formatted in easy-to-read tables as shown below:
36
+
37
+ ```
38
+ +---------------------------------+--------------+
39
+ | Group Creates |
40
+ +---------------------------------+--------------+
41
+ | Group Name | Parent Group |
42
+ +---------------------------------+--------------+
43
+ | Computers.2k8sso.local | nil |
44
+ | local | nil |
45
+ | 2k8sso.local | nil |
46
+ | Domain Controllers.2k8sso.local | nil |
47
+ +---------------------------------+--------------+
48
+ +---------------------------------+------------+--------------+
49
+ | Group Moves |
50
+ +---------------------------------+------------+--------------+
51
+ | Group | Old Parent | New Parent |
52
+ +---------------------------------+------------+--------------+
53
+ | Computers.2k8sso.local | | 2k8sso.local |
54
+ | 2k8sso.local | | local |
55
+ | Domain Controllers.2k8sso.local | | 2k8sso.local |
56
+ +---------------------------------+------------+--------------+
57
+ +----------------+------------+------------------------+
58
+ | Computer Moves |
59
+ +----------------+------------+------------------------+
60
+ | # of computers | from group | to group |
61
+ +----------------+------------+------------------------+
62
+ | 2 | Protect | Computers.2k8sso.local |
63
+ | 2 | Audit | Computers.2k8sso.local |
64
+ +----------------+------------+------------------------+
65
+ ```
66
+
67
+ Applying the -a option will tell the command to apply the changes, it will prompt the user to continue with a y/n after showing the _dry run_.
68
+
69
+
70
+
71
+
72
+
73
+
74
+ ## Config File
75
+
76
+ The config file holds our user/password information for the API/LDAP servers. It follows a specific format and a template is provided below:
77
+
78
+
79
+ ```
80
+ #config.yml
81
+ :ldap:
82
+ :host: # LDAP hostname
83
+ :domain: # domain of LDAP tree
84
+ :credentials:
85
+ :un: # server username
86
+ :pw: # server password
87
+ :schema:
88
+ :filter: "computer" # default as computer
89
+ :amp:
90
+ :host: # api url for AMP
91
+ :api:
92
+ :third_party: # third party code
93
+ :key: # api key
94
+ :version: "v1" # default version is v1
95
+ ```
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'amp4e_ldap_tool/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "amp4e_ldap_tool"
8
+ spec.version = Amp4eLdapTool::VERSION
9
+ spec.authors = ["vbakala"]
10
+ spec.email = ["vbakala@cisco.com"]
11
+
12
+ spec.summary = %q{Write a short summary, because Rubygems requires one.}
13
+ spec.description = %q{Write a longer description or delete this line.}
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.bindir = "exe"
17
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.12"
21
+ spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_development_dependency "rspec", "~> 3.0"
23
+ spec.add_dependency "thor", "~> 0.19.4"
24
+ spec.add_dependency "net-ldap", "~> 0.15.0"
25
+ spec.add_dependency "terminal-table", "~> 1.7", ">= 1.7.3"
26
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "amp4e_ldap_tool"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "amp4e_ldap_tool/cli"
4
+
5
+ Amp4eLdapTool::CLI.start
@@ -0,0 +1,86 @@
1
+ require "amp4e_ldap_tool/version"
2
+ require "amp4e_ldap_tool/errors"
3
+ require "amp4e_ldap_tool/cisco_amp"
4
+ require "amp4e_ldap_tool/ldap_scrape"
5
+ require "terminal-table"
6
+
7
+ module Amp4eLdapTool
8
+
9
+ def self.dry_run(amp, ldap)
10
+ #TODO validate input
11
+ data = {created_groups: [], group_moves: [], pc_moves: []}
12
+ adj = amp.make_list(amp.get(:computers), amp.get(:groups))
13
+ ldap.groups.each do |group|
14
+ if adj[group].nil?
15
+ data[:created_groups] << [group, "nil"]
16
+ adj[group] = { object: nil, parent: nil }
17
+ end
18
+ unless adj[group][:parent] == ldap.parent(group)
19
+ data[:group_moves] << [group, adj[group][:parent], ldap.parent(group)]
20
+ adj[group][:parent] = ldap.parent(group)
21
+ end
22
+ end
23
+ counter = {}
24
+ ldap.entries.each do |entry|
25
+ computername = entry.dnshostname.first.downcase
26
+ unless adj[computername].nil?
27
+ if adj[computername][:parent] != ldap.parent(entry.dn)
28
+ old_name = adj[computername][:parent]
29
+ new_name = ldap.parent(entry.dn)
30
+ if counter[old_name].nil?
31
+ counter[old_name] = {new_name => 1}
32
+ else
33
+ counter[old_name][new_name].nil? ? counter[old_name][new_name] = 1
34
+ : counter[old_name][new_name] += 1
35
+ end
36
+ end
37
+ end
38
+ end
39
+ counter.keys.each do |old_name|
40
+ counter[old_name].keys.each do |new_name|
41
+ data[:pc_moves] << [counter[old_name][new_name], old_name, new_name]
42
+ end
43
+ end
44
+ generate_table(data)
45
+ end
46
+
47
+ def self.push_changes(amp, ldap)
48
+ #TODO validate input
49
+ adj = amp.make_list(amp.get(:computers), amp.get(:groups))
50
+ ldap.groups.each do |group|
51
+ if adj[group].nil?
52
+ puts "creating group..."
53
+ g = amp.create_group(group)
54
+ adj[group] = { object: g, parent: g.parent[:name] }
55
+ end
56
+ unless adj[group][:parent] == ldap.parent(group)
57
+ puts "updating group parent..."
58
+ amp.update_group(adj[group][:object].guid, adj[ldap.parent(group)][:object].guid)
59
+ adj[group][:parent] = ldap.parent(group)
60
+ end
61
+ end
62
+ ldap.entries.each do |entry|
63
+ computername = entry.dnshostname.first.downcase
64
+ parent_name = ldap.parent(entry.dn)
65
+ unless adj[computername].nil?
66
+ if adj[computername][:parent] != parent_name
67
+ puts "moving computer..."
68
+ amp.update_computer(adj[computername][:object].guid, adj[parent_name][:object].guid)
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def self.generate_table(table_data)
77
+ #TODO validate input
78
+ puts Terminal::Table.new(title: "Group Creates", rows: table_data[:created_groups],
79
+ headings: ["Group Name", "Parent Group"])
80
+ puts Terminal::Table.new(title: "Group Moves", rows: table_data[:group_moves],
81
+ headings: ["Group", "Old Parent", "New Parent"])
82
+ puts Terminal::Table.new(title: "Computer Moves", rows: table_data[:pc_moves],
83
+ headings: ["# of computers", "from group", "to group" ])
84
+ end
85
+
86
+ end
@@ -0,0 +1,151 @@
1
+ require 'net/http'
2
+ require 'yaml'
3
+ require 'amp4e_ldap_tool/errors'
4
+ require 'amp4e_ldap_tool/endpoints'
5
+ require 'json'
6
+
7
+ module Amp4eLdapTool
8
+ GUID = /\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/
9
+ X_RATELIMIT_REMAINING = 'x-ratelimit-remaining'
10
+ X_RATELIMIT_RESET = 'x-ratelimit-reset'
11
+
12
+ class CiscoAMP
13
+
14
+ attr_reader :base_url, :version, :email, :third_party, :api_key
15
+
16
+ def initialize(config_file = "config.yml")
17
+ config = YAML.load_file(config_file)
18
+ confirm_config(config)
19
+ @base_url = config[:amp][:host]
20
+ @version = config[:amp][:api][:version]
21
+ @email = config[:amp][:email]
22
+ @third_party = config[:amp][:api][:third_party]
23
+ @api_key = config[:amp][:api][:key]
24
+ end
25
+
26
+ def get(endpoint)
27
+ url = URI(@base_url + "/#{@version}/#{endpoint}")
28
+ get = Net::HTTP::Get.new(url)
29
+ response = send(get, url)
30
+ parse_response(response, endpoint.to_sym)
31
+ end
32
+
33
+ def update_computer(computer_guid, new_guid)
34
+ validate_guid([computer_guid, new_guid])
35
+ url = URI(@base_url + "/#{@version}/computers/#{computer_guid}")
36
+ patch = Net::HTTP::Patch.new(url)
37
+ body = { group_guid: new_guid }
38
+ send(patch, url, body)
39
+ end
40
+
41
+ def update_group(group_guid, parent = nil)
42
+ validate_guid([group_guid])
43
+ url = URI(@base_url + "/#{@version}/groups/#{group_guid}/parent")
44
+ patch = Net::HTTP::Patch.new(url)
45
+ body = { parent_group_guid: parent }
46
+ response = send(patch, url, body)
47
+ end
48
+
49
+ def create_group(group_name, desc = "Imported from LDAP")
50
+ url = URI(@base_url + "/#{@version}/groups/")
51
+ post = Net::HTTP::Post.new(url)
52
+ body = { name: group_name, email: @email,
53
+ description: desc }
54
+ send(post, url, body)
55
+ end
56
+
57
+ def make_list(computers, groups)
58
+ adj = {}
59
+ groups.each do |group|
60
+ adj[group.name] = { object: group, parent: group.parent[:name] }
61
+ end
62
+ computers.each do |pc|
63
+ group = groups.find{ |g| g.guid == pc.group_guid }
64
+ adj[pc.name.downcase] = { object: pc, parent: group.name }
65
+ end
66
+ adj
67
+ end
68
+
69
+ private
70
+
71
+ def send(http_request, url, body = {})
72
+ http_request.basic_auth(@third_party, @api_key)
73
+ http_request.set_form_data(body) unless body.empty?
74
+ check_response do
75
+ Net::HTTP.start(url.hostname, url.port) do |http|
76
+ http.request(http_request)
77
+ end
78
+ end
79
+ end
80
+
81
+ def check_response
82
+ begin
83
+ response = yield
84
+ response_head = response.to_hash
85
+ response_body = JSON.parse(response.body)
86
+
87
+ case response.msg.downcase.tr(" ","_").to_sym
88
+ when :ok
89
+ response_notification = response.body
90
+ when :created
91
+ response_notification = Amp4eLdapTool::AMP::Group.new(response_body["data"])
92
+ when :accepted
93
+ response_notification = response.msg
94
+ when :too_many_requests
95
+ raise AMPTooManyRequestsError
96
+ when :bad_request
97
+ raise AMPBadRequestError.new(msg: response_body["errors"])
98
+ when :unauthorized
99
+ raise AMPUnauthorizedError.new(msg: response_body["errors"])
100
+ else
101
+ raise AMPResponseError.new(msg: "code: " + response.msg + " body: " + response.body)
102
+ end
103
+ rescue AMPTooManyRequestsError
104
+ sleep_seconds = response_head[Amp4eLdapTool::X_RATELIMIT_RESET].to_i
105
+ puts "Ratelimit Reached, sleeping for #{sleep_seconds} second(s)"
106
+ sleep(sleep_seconds)
107
+ retry
108
+ end
109
+ response_notification
110
+ end
111
+
112
+ def parse_response(message, endpoint)
113
+ endpoints = []
114
+ parse = JSON.parse(message)
115
+ parse["data"].each do |item|
116
+ case endpoint
117
+ when :computers
118
+ endpoints << Amp4eLdapTool::AMP::Computer.new(item)
119
+ when :groups
120
+ endpoints << Amp4eLdapTool::AMP::Group.new(item)
121
+ when :policies
122
+ endpoints << Amp4eLdapTool::AMP::Policy.new(item)
123
+ else
124
+ raise AMPResponseError.new(msg: "Parsing GET error for #{endpoint}")
125
+ end
126
+ end
127
+ endpoints
128
+ end
129
+
130
+ def validate_guid(guids)
131
+ guids.each do |guid|
132
+ if Amp4eLdapTool::GUID.match(guid).nil?
133
+ raise AMPInvalidFormatError
134
+ end
135
+ end
136
+ end
137
+
138
+ def confirm_config(config)
139
+ raise AMPConfigError if config[:amp][:api][:third_party].nil?
140
+ raise AMPConfigError if config[:amp][:api][:key].nil?
141
+ raise AMPConfigError if config[:amp][:api][:version].nil?
142
+ begin
143
+ Net::HTTP::Get.new(URI(config[:amp][:host]))
144
+ rescue TypeError
145
+ raise AMPBadURIError
146
+ rescue ArgumentError
147
+ raise AMPConfigError
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,159 @@
1
+ require 'thor'
2
+ require 'amp4e_ldap_tool/cisco_amp'
3
+ require 'amp4e_ldap_tool/ldap_scrape'
4
+ require 'amp4e_ldap_tool'
5
+ require 'terminal-table'
6
+
7
+ module Amp4eLdapTool
8
+ class CLI < Thor
9
+
10
+ desc "amp --[groups|computers|policies]", "Gets groups, computer, and/or policies from AMP"
11
+ long_desc <<-LONGDESC
12
+ groupsync amp will get a list of groups, policies, and computers from AMP,
13
+ with the specified options above.
14
+
15
+ For example the following command will fetch the list of computers from amp:
16
+
17
+ > $ groupsync amp -c
18
+ LONGDESC
19
+ method_option :computers, aliases: "-c"
20
+ method_option :groups, aliases: "-g"
21
+ method_option :policies, aliases: "-p"
22
+ method_option :table, aliases: "-t"
23
+ def amp
24
+ display_resources(Amp4eLdapTool::CiscoAMP.new, options)
25
+ end
26
+
27
+ desc "ldap --[groups|computers|distinguished]", "Gets groups, computer, and/or distinguished names from LDAP"
28
+ long_desc <<-LONGDESC
29
+ groupsync ldap will get a list of groups, distinguished names, and computers from AMP,
30
+ with the specified options above.
31
+
32
+ For example the following command will fetch the list of computers from ldap:
33
+
34
+ > $ groupsync ldap -c
35
+ LONGDESC
36
+ method_option :computers, aliases: "-c"
37
+ method_option :groups, aliases: "-g"
38
+ method_option :distinguished, aliases: "-d"
39
+ method_option :table, aliases: "-t"
40
+ def ldap
41
+ ldap = Amp4eLdapTool::LDAPScrape.new
42
+
43
+ if options[:table]
44
+ options.keys.each do |name|
45
+ rows = []
46
+ unless name == 'table'
47
+ if name == 'computers'
48
+ ldap.entries.each {|entry| rows << [entry.dnshostname]}
49
+ elsif name == 'distinguished'
50
+ ldap.entries.each {|entry| rows << [entry.dn]}
51
+ elsif name == 'groups'
52
+ ldap.groups.each {|entry| rows << [entry]}
53
+ end
54
+ puts Terminal::Table.new(:headings => [name], :rows => rows)
55
+ end
56
+ end
57
+ else
58
+ puts ldap.groups unless options[:groups].nil?
59
+ ldap.entries.each {|entry| puts entry.dnshostname} unless options[:computers].nil?
60
+ ldap.entries.each {|entry| puts entry.dn} unless options[:distinguished].nil?
61
+ end
62
+ end
63
+
64
+ long_desc <<-LONGDESC
65
+ Moves a computer to a specified group, requires the new group GUID.
66
+
67
+ For example the following command will move a specific computer(00000000-0000-0000-0000-000000000000)
68
+ to group(11111111-1111-1111-1111-111111111111).
69
+
70
+ > $ groupsync move 00000000-0000-0000-0000-000000000000 11111111-1111-1111-1111-111111111111
71
+ LONGDESC
72
+ desc "move PC GUID", "Moves a PC to a specified group, requires the new groups GUID"
73
+ def move(computer, new_guid)
74
+ amp = Amp4eLdapTool::CiscoAMP.new
75
+ puts amp.move_computer(computer, new_guid)
76
+ end
77
+
78
+ long_desc <<-LONGDESC
79
+ Creates a group with the specified name.
80
+
81
+ For example the following command will create a group with the name ExampleGroup:
82
+
83
+ > $ groupsync create ExampleGroup
84
+ LONGDESC
85
+ desc "create NAME", "Creates a group with the name of NAME"
86
+ method_option :desc, aliases: "-d"
87
+ def create(name)
88
+ amp = Amp4eLdapTool::CiscoAMP.new
89
+ puts amp.create_group(name).name unless options[:desc]
90
+ puts amp.create_group(name, options[:desc]).name if options[:desc]
91
+ end
92
+
93
+ long_desc <<-LONGDESC
94
+ Moves a specified group under a new parent.
95
+
96
+ For example the following command will move the group(00000000-0000-0000-0000-000000000000)
97
+ under parent(11111111-1111-1111-1111-111111111111):
98
+
99
+ > $ groupsync move_group 00000000-0000-0000-0000-000000000000 11111111-1111-1111-1111-111111111111
100
+ LONGDESC
101
+ desc "move_group GUID PARENT", "Moves a group under a new parent"
102
+ def move_group(guid, parent_guid)
103
+ amp = Amp4eLdapTool::CiscoAMP.new
104
+ puts amp.update_group(guid, parent_guid)
105
+ end
106
+
107
+
108
+ desc "make_changes", "Shows a dry run of changes, and prompts to execute"
109
+ long_desc <<-LONGDESC
110
+ Shows a dry run of changes in tabular form:
111
+
112
+ Executing 'make_changes' on its own produces a dry run, while the '-a' option
113
+ prompts the user to apply the changes. The '-f' option is used for
114
+ scripting and executes the changes without a prompt or dry-run report.
115
+
116
+ >$ amp4e_ldap_tool make_changes -a \x5
117
+ ... \x5
118
+ Do you want to continue? [y, n]\x5
119
+
120
+ LONGDESC
121
+ method_option :apply, aliases: "-a"
122
+ method_option :force, aliases: "-f"
123
+ def make_changes
124
+ answer = "n"
125
+ amp = Amp4eLdapTool::CiscoAMP.new
126
+ ldap = Amp4eLdapTool::LDAPScrape.new
127
+
128
+ if (options.empty?)
129
+ Amp4eLdapTool.dry_run(amp, ldap)
130
+ elsif (options[:apply])
131
+ Amp4eLdapTool.dry_run(amp, ldap)
132
+ answer = ask("Do you want to continue?", limited_to: ["y","n"]) if options[:apply]
133
+ Amp4eLdapTool.push_changes(amp, ldap) if (answer == "y")
134
+ elsif (options[:force])
135
+ Amp4eLdapTool.push_changes(amp, ldap)
136
+ end
137
+ end
138
+
139
+ private
140
+
141
+ def display_resources(amp, options)
142
+ if options[:table]
143
+ options.keys.each do |name|
144
+ rows = []
145
+ unless name == 'table'
146
+ amp.get(name).each {|endpoint| rows << [endpoint.name]}
147
+ puts Terminal::Table.new(:headings => [name], :rows => rows)
148
+ end
149
+ end
150
+ else
151
+ options.keys.each do |endpoints|
152
+ amp.get(endpoints).each do |endpoint|
153
+ puts endpoint.name
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,49 @@
1
+ module Amp4eLdapTool
2
+ module AMP
3
+ class Computer
4
+ attr_accessor :name, :guid, :link, :active,
5
+ :group_guid, :policy, :os
6
+
7
+ def initialize(json)
8
+ @name = json["hostname"]
9
+ @guid = json["connector_guid"]
10
+ @active = json["active"]
11
+ @group_guid = json["group_guid"]
12
+ @os = json["operating_system"]
13
+ @link = { computer: json["links"]["computer"],
14
+ trajectory: json["links"]["trajectory"],
15
+ group: json["links"]["group"]}
16
+ @policy = { name: json["policy"]["name"],
17
+ guid: json["policy"]["guid"] }
18
+ end
19
+ end
20
+
21
+ class Group
22
+ attr_accessor :name, :description, :guid, :parent, :link
23
+
24
+ def initialize(json)
25
+ @name = json["name"]
26
+ @guid = json["guid"]
27
+ @description = json["description"]
28
+ @parent = (json["ancestry"].nil?) ? {} :
29
+ {name: json["ancestry"].first["name"],
30
+ guid: json["ancestry"].first["guid"]}
31
+ end
32
+ end
33
+
34
+ class Policy
35
+ attr_accessor :name, :description, :guid, :product, :default,
36
+ :serial_number, :link
37
+
38
+ def initialize(json)
39
+ @name = json["name"]
40
+ @guid = json["guid"]
41
+ @description = json["description"]
42
+ @product = json["product"]
43
+ @default = json["default"]
44
+ @serial_number = json["serial_number"]
45
+ @link = json["links"]["policy"]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,49 @@
1
+ module Amp4eLdapTool
2
+ class AMPConfigError < StandardError
3
+ def initialize(msg: "The AMP section of the configuration file is not formatted properly" )
4
+ super
5
+ end
6
+ end
7
+
8
+ class LDAPConfigError < StandardError
9
+ def initialize(msg: "The LDAP Section of the configuration file is not formatted properly")
10
+ super
11
+ end
12
+ end
13
+
14
+ class AMPTooManyRequestsError < StandardError
15
+ def initialize(msg: "The ratelimit has been excedded")
16
+ super
17
+ end
18
+ end
19
+
20
+ class AMPBadURIError < StandardError
21
+ def initialize(msg: "The amp:host in your config file contains an invalid hostname")
22
+ super
23
+ end
24
+ end
25
+
26
+ class AMPInvalidFormatError < ArgumentError
27
+ def initialize(msg: "The GUID provided does not follow the correct format")
28
+ super
29
+ end
30
+ end
31
+
32
+ class AMPResponseError < StandardError
33
+ def initialize(msg: "The AMP Server returned a non-OK response")
34
+ super
35
+ end
36
+ end
37
+
38
+ class AMPUnauthorizedError < AMPResponseError
39
+ def initialize(msg: "Third_party/API credentials appear to be invalid")
40
+ super
41
+ end
42
+ end
43
+
44
+ class AMPBadRequestError < AMPResponseError
45
+ def initialize(msg: "A Bad request was made to the server")
46
+ super
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,69 @@
1
+ require 'net/ldap'
2
+ require 'yaml'
3
+ require 'json'
4
+
5
+ module Amp4eLdapTool
6
+ class LDAPScrape
7
+
8
+ attr_reader :entries
9
+
10
+ def initialize(filename = 'config.yml')
11
+ cfg = YAML.load_file(filename)
12
+
13
+ attributes = ["cn", "dnshostname"]
14
+ base = make_dn(cfg[:ldap][:domain])
15
+ filter = Net::LDAP::Filter.eq('objectClass', cfg[:ldap][:schema][:filter])
16
+ server = Net::LDAP.new(
17
+ host: cfg[:ldap][:host],
18
+ auth: {
19
+ method: :simple,
20
+ username: "#{cfg[:ldap][:credentials][:un]}@#{cfg[:ldap][:domain]}",
21
+ password: cfg[:ldap][:credentials][:pw]}
22
+ )
23
+ @entries = server.search(base: base, filter: filter, attributes: attributes) do |entry|
24
+ entry
25
+ end
26
+ end
27
+
28
+ def groups
29
+ dn_paths = []
30
+ @entries.each do |entry|
31
+ names = split_dn(entry.dn); names.shift; names.reverse!
32
+ temp_names = names.clone
33
+ names.each do
34
+ name = temp_names.inject{|glob, name| "#{name}.#{glob}"}
35
+ dn_paths << name
36
+ temp_names.pop
37
+ end
38
+ end
39
+ dn_paths.uniq.reverse
40
+ end
41
+
42
+ def parent(entry_name)
43
+ names = split_dn(entry_name) if entry_name.include?("=")
44
+ names = entry_name.split(".") if not entry_name.include?("=")
45
+ names.shift
46
+ unless names.empty?
47
+ parent_string = names.join(".")
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def make_dn(domain_name)
54
+ output = ''
55
+ domain_name.split('.').each do |name|
56
+ output << "dc=#{name},"
57
+ end
58
+ output.chomp(',')
59
+ end
60
+
61
+ def split_dn(dn)
62
+ names = []
63
+ dn.split(",").each do |attribute|
64
+ names << attribute.split("=").last
65
+ end
66
+ names
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ module Amp4eLdapTool
2
+ VERSION = "0.0.3"
3
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: amp4e_ldap_tool
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - vbakala
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-05-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: thor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.19.4
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.19.4
69
+ - !ruby/object:Gem::Dependency
70
+ name: net-ldap
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.15.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.15.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: terminal-table
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.7'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 1.7.3
93
+ type: :runtime
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '1.7'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.7.3
103
+ description: Write a longer description or delete this line.
104
+ email:
105
+ - vbakala@cisco.com
106
+ executables:
107
+ - amp4e_ldap_tool
108
+ extensions: []
109
+ extra_rdoc_files: []
110
+ files:
111
+ - ".gitignore"
112
+ - ".rspec"
113
+ - ".travis.yml"
114
+ - Gemfile
115
+ - README.md
116
+ - Rakefile
117
+ - amp4e_ldap_tool.gemspec
118
+ - bin/console
119
+ - bin/setup
120
+ - exe/amp4e_ldap_tool
121
+ - lib/amp4e_ldap_tool.rb
122
+ - lib/amp4e_ldap_tool/cisco_amp.rb
123
+ - lib/amp4e_ldap_tool/cli.rb
124
+ - lib/amp4e_ldap_tool/endpoints.rb
125
+ - lib/amp4e_ldap_tool/errors.rb
126
+ - lib/amp4e_ldap_tool/ldap_scrape.rb
127
+ - lib/amp4e_ldap_tool/version.rb
128
+ homepage:
129
+ licenses: []
130
+ metadata: {}
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.4.5
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: Write a short summary, because Rubygems requires one.
151
+ test_files: []