amp4e_ldap_tool 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []