ucert 0.2.57

Sign up to get free protection for your applications and to get access to all the features.
Files changed (252) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +134 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.rdoc +61 -0
  5. data/Rakefile +8 -0
  6. data/TODO +5 -0
  7. data/bin/ad_dump +74 -0
  8. data/bin/ad_update +48 -0
  9. data/bin/adgrep +149 -0
  10. data/bin/adp_dump +70 -0
  11. data/bin/aix_dump +69 -0
  12. data/bin/audiolog_dump +69 -0
  13. data/bin/bloomberg_dump +69 -0
  14. data/bin/check21_dump +69 -0
  15. data/bin/citidirect_be_dump +69 -0
  16. data/bin/citidirect_sec_dump +69 -0
  17. data/bin/citrixsf_dump +70 -0
  18. data/bin/clear_par_dump +70 -0
  19. data/bin/cmbrun_ny_dump +76 -0
  20. data/bin/cvm_dump +70 -0
  21. data/bin/db_direct_dump +69 -0
  22. data/bin/egifts_dump +68 -0
  23. data/bin/equinix_dump +69 -0
  24. data/bin/frb_dump +69 -0
  25. data/bin/go_contact_dump +16 -0
  26. data/bin/jpm_dump +69 -0
  27. data/bin/madison535_dump +70 -0
  28. data/bin/mantis_dump +79 -0
  29. data/bin/prime_dump +79 -0
  30. data/bin/sage100_dump +69 -0
  31. data/bin/sharefile_dump +69 -0
  32. data/bin/som_dump +74 -0
  33. data/bin/stb_dump +69 -0
  34. data/bin/swift_dump +79 -0
  35. data/bin/swift_online_dump +69 -0
  36. data/bin/t24_dump +79 -0
  37. data/bin/vpn_dump +69 -0
  38. data/bin/wms_dump +79 -0
  39. data/bin/yst_dump +79 -0
  40. data/data/ad/ad_delta.txt +94 -0
  41. data/data/ad/hosts +421 -0
  42. data/data/ad/hosts.old +597 -0
  43. data/data/ad/hosts_old +597 -0
  44. data/data/ad/ldap_computer.txt +19028 -0
  45. data/data/ad/ldap_person.txt +41241 -0
  46. data/data/adp/Active Employee Report.xlsx +0 -0
  47. data/data/adp/adp_user_map.txt +141 -0
  48. data/data/aix/EGIFTS1.txt +239 -0
  49. data/data/aix/NYSWIFT1.txt +222 -0
  50. data/data/aix/T24_APP1.txt +300 -0
  51. data/data/aix/T24_DBP.txt +252 -0
  52. data/data/aix/aix_user_map.txt +46 -0
  53. data/data/alliance_swift/Swift_Operator_Details.xlsx +0 -0
  54. data/data/alliance_swift/Swift_Operator_Profiles_Details.xlsx +0 -0
  55. data/data/alliance_swift/swift_operator_map.txt +22 -0
  56. data/data/audiolog/Capture_audiolog.PNG +0 -0
  57. data/data/bloomberg/AccountData.csv +2 -0
  58. data/data/bloomberg/Capture_SID_download.PNG +0 -0
  59. data/data/bloomberg/current_subscriptions.csv +11 -0
  60. data/data/check21/Capture_check21_users.PNG +0 -0
  61. data/data/citidirect_be/Capture.PNG +0 -0
  62. data/data/citidirect_be/Capture_new.PNG +0 -0
  63. data/data/citidirect_be/Capture_new_new.PNG +0 -0
  64. data/data/citidirect_be/UserProfileEntitlementReport.pdf +0 -0
  65. data/data/citidirect_be/UserProfileEntitlementsReport.old.xlsx +0 -0
  66. data/data/citidirect_be/UserProfileEntitlementsReport.xlsx +0 -0
  67. data/data/citidirect_be/be_user_map.txt +11 -0
  68. data/data/citidirect_securities/Capture.PNG +0 -0
  69. data/data/citidirect_securities/User_Entitlements_Report___CLNT.dat +19 -0
  70. data/data/citidirect_securities/User_Entitlements_Report___CLNT.xml +75 -0
  71. data/data/citidirect_securities/citidirect_securities_user_map.txt +10 -0
  72. data/data/citrix_sharefile/ShareFile_Access_Report.xlsx +0 -0
  73. data/data/citrix_sharefile/sharefile_user_map.txt +33 -0
  74. data/data/clear_par/ClearPar User Report.xlsx +0 -0
  75. data/data/clear_par/clear_par_user_map.txt +25 -0
  76. data/data/cmbrun_ny/CMBNY_Position_Rpt.xlsx +0 -0
  77. data/data/cmbrun_ny/CMBRUN_USER_RPT.xlsx +0 -0
  78. data/data/cmbrun_ny/Capture_cmbrun.PNG +0 -0
  79. data/data/cmbrun_ny/Capture_cmbrun_position.PNG +0 -0
  80. data/data/cmbrun_ny/crny_access_user_map.txt +55 -0
  81. data/data/cvm/cvm_user_func.xlsx +0 -0
  82. data/data/cvm/cvm_user_list.xlsx +0 -0
  83. data/data/cvm/cvm_user_map.txt +56 -0
  84. data/data/cvm/cvm_user_role.xlsx +0 -0
  85. data/data/db_direct/Capture_main.PNG +0 -0
  86. data/data/db_direct/Capture_rpt.PNG +0 -0
  87. data/data/db_direct/accountpermission.xlsx +0 -0
  88. data/data/db_direct/db_direct_user_map.txt +8 -0
  89. data/data/db_direct/di_direct_user_map.txt +0 -0
  90. data/data/db_direct/userfulldetail_2016010813232300644912.pdf +0 -0
  91. data/data/equinix/Secured Access List_CHINA MERCHANTS BANK.xlsx +0 -0
  92. data/data/equinix/equinix_user_map.txt +29 -0
  93. data/data/fis_egifts/CHINA_MERCHANTS_BANK_-_USER_ACCOUNT_FUNCTION_REPORT.xlsx +0 -0
  94. data/data/fis_egifts/egifts_user_map.txt +113 -0
  95. data/data/fis_prime/Prime_Operator_Rights_Report.xml +41958 -0
  96. data/data/fis_prime/Prime_Operator_Status_Report.xml +1827 -0
  97. data/data/fis_prime/Prime_Operators_and_Roles_Report.xml +1505 -0
  98. data/data/fis_prime/Prime_Rights_by_Role_Report.xml +22726 -0
  99. data/data/fis_prime/prime_user_map.txt +77 -0
  100. data/data/frb/FRB_Subscriber_Roles_Report.xlsx +0 -0
  101. data/data/frb/frb_user_map.txt +22 -0
  102. data/data/go_contact/go_contact.xlsx +0 -0
  103. data/data/go_contact/go_user_map.txt +134 -0
  104. data/data/go_contact/title_level_map.txt +141 -0
  105. data/data/jpm_access/Capture.PNG +0 -0
  106. data/data/jpm_access/jpm_access_user_map.txt +13 -0
  107. data/data/jpm_access/jpm_user_entitlements_details.txt +194 -0
  108. data/data/jpm_access/jpm_user_groupentitlements_details.txt +2 -0
  109. data/data/madison535/535madison_bldg_pass.xlsx +0 -0
  110. data/data/madison535/535madison_bldg_pass_2.xlsx +0 -0
  111. data/data/madison535/madison535_user_map.txt +191 -0
  112. data/data/mantis/Mantis_AccessLevels.xlsx +0 -0
  113. data/data/mantis/Mantis_ActiveUsers_Rpt.xlsx +0 -0
  114. data/data/mantis/mantis_access_user_map.txt +128 -0
  115. data/data/sage100/Capture_Sage100_Rpt.PNG +0 -0
  116. data/data/sage100/Capture_Sage100_Rpt_2.PNG +0 -0
  117. data/data/sage100/SY_UserReport_RolePreferencesDetails.xlsx +0 -0
  118. data/data/sage100/SY_UserReport_RoleTaskPermissionsDetails.xlsx +0 -0
  119. data/data/sage100/sy_user_map.txt +14 -0
  120. data/data/som/som_user_map.txt +40 -0
  121. data/data/som/som_user_report.csv +329 -0
  122. data/data/stb/STB_USERS.csv +177 -0
  123. data/data/stb/STB_USERS.pdf +0 -0
  124. data/data/stb/stb_user_map.txt +33 -0
  125. data/data/swift_online/UserReport.xlsx +0 -0
  126. data/data/swift_online/swo_access_user_map.txt +18 -0
  127. data/data/t24/T24_Grp_Rpt.csv +484 -0
  128. data/data/t24/T24_User_Rpt.csv +567 -0
  129. data/data/t24/t24_grp.xml +2904 -0
  130. data/data/t24/t24_user_map.txt +197 -0
  131. data/data/t24/t24_usr.xml +9628 -0
  132. data/data/vpn/Capture_VPN.PNG +0 -0
  133. data/data/wms/role_rpt.txt +451 -0
  134. data/data/wms/user_rpt.txt +55 -0
  135. data/data/wms/wms_user_map.txt +55 -0
  136. data/data/yst/YiShiTong_Org.csv +21 -0
  137. data/data/yst/YiShiTong_User.csv +163 -0
  138. data/data/yst/yst_user_map.txt +163 -0
  139. data/demos/filter_email.rb +19 -0
  140. data/demos/idm_ad_reload.rb +164 -0
  141. data/lib/ucert.rb +82 -0
  142. data/lib/ucert/ad_tracker.rb +694 -0
  143. data/lib/ucert/adp_payroll_tracker.rb +189 -0
  144. data/lib/ucert/aix_tracker.rb +175 -0
  145. data/lib/ucert/alliance_swift_tracker.rb +300 -0
  146. data/lib/ucert/audiolog_tracker.rb +67 -0
  147. data/lib/ucert/bloomberg_tracker.rb +96 -0
  148. data/lib/ucert/check21_tracker.rb +95 -0
  149. data/lib/ucert/citidirect_be_tracker.rb +418 -0
  150. data/lib/ucert/citidirect_securities_tracker.rb +230 -0
  151. data/lib/ucert/citrix_sharefile_tracker.rb +196 -0
  152. data/lib/ucert/clear_par_tracker.rb +187 -0
  153. data/lib/ucert/cmbrun_ny_tracker.rb +244 -0
  154. data/lib/ucert/cvm_tracker.rb +230 -0
  155. data/lib/ucert/db_direct_tracker.rb +205 -0
  156. data/lib/ucert/equinix_tracker.rb +202 -0
  157. data/lib/ucert/fis_egifts_tracker.rb +249 -0
  158. data/lib/ucert/fis_prime_tracker.rb +391 -0
  159. data/lib/ucert/frb_tracker.rb +232 -0
  160. data/lib/ucert/go_contact_tracker.rb +778 -0
  161. data/lib/ucert/jpm_access_tracker.rb +205 -0
  162. data/lib/ucert/madison535_tracker.rb +273 -0
  163. data/lib/ucert/mantis_tracker.rb +249 -0
  164. data/lib/ucert/sage100_tracker.rb +355 -0
  165. data/lib/ucert/som_tracker.rb +223 -0
  166. data/lib/ucert/stb_tracker.rb +199 -0
  167. data/lib/ucert/swift_online_tracker.rb +197 -0
  168. data/lib/ucert/t24_tracker.rb +342 -0
  169. data/lib/ucert/utils/utils.rb +200 -0
  170. data/lib/ucert/vpn_tracker.rb +94 -0
  171. data/lib/ucert/wms_tracker.rb +240 -0
  172. data/lib/ucert/yst_tracker.rb +264 -0
  173. data/test/ad_testfiles/ldap_computer_test.txt +21 -0
  174. data/test/ad_testfiles/ldap_person_test.txt +21 -0
  175. data/test/aix_testfiles/application1.txt +7 -0
  176. data/test/aix_testfiles/application2.txt +15 -0
  177. data/test/alliance_swift_testfiles/Swift_Operator_Details_Test.xlsx +0 -0
  178. data/test/alliance_swift_testfiles/Swift_Operator_Profiles_Details_Test.xlsx +0 -0
  179. data/test/alliance_swift_testfiles/swift_operator_map_test.txt +55 -0
  180. data/test/alliance_swift_testfiles/swift_operator_map_test_2.txt +55 -0
  181. data/test/alliance_swift_testfiles/swift_operator_map_test_format_fixed.txt +55 -0
  182. data/test/citidirect_be_testfiles/UserProfileEntitlementsReport_Test.xlsx +0 -0
  183. data/test/citidirect_securities_testfiles/User_Entitlements_Report___CLNT_Test.xml +48 -0
  184. data/test/citrix_sharefile_testfiles/ShareFile_Access_Report_Test.xlsx +0 -0
  185. data/test/cmbrun_ny_testfiles/CMBNY_Position_Rpt_02242016_test.xlsx +0 -0
  186. data/test/cmbrun_ny_testfiles/CMBRUN_USER_RPT_Test.xlsx +0 -0
  187. data/test/db_direct_testfiles/accountpermission_Test.xlsx +0 -0
  188. data/test/equinix_testfiles/Secured Access List_CHINA MERCHANTS BANK_TEST.xlsx +0 -0
  189. data/test/fis_egifts_testfiles/CHINA_MERCHANTS_BANK_-_USER_ACCOUNT_FUNCTION_REPORT_TEST.xlsx +0 -0
  190. data/test/fis_prime_testfiles/Prime_Operator_Rights_Report_Test.xml +158 -0
  191. data/test/fis_prime_testfiles/Prime_Operator_Status_Report_Copy.xml +1659 -0
  192. data/test/fis_prime_testfiles/Prime_Operator_Status_Report_Test.xml +51 -0
  193. data/test/fis_prime_testfiles/Prime_Operators_and_Roles_Report_Copy.xml +1360 -0
  194. data/test/fis_prime_testfiles/Prime_Operators_and_Roles_Report_Test.xml +45 -0
  195. data/test/fis_prime_testfiles/Prime_Rights_by_Role_Report_Test.xml +65 -0
  196. data/test/fis_prime_testfiles/prime_user_map.txt +3 -0
  197. data/test/frb_testfiles/FRB_Subscriber_Roles_Report_Test.xlsx +0 -0
  198. data/test/go_contact_testfiles/go_contact_test.xlsx +0 -0
  199. data/test/jpm_access_testfiles/Capture.PNG +0 -0
  200. data/test/jpm_access_testfiles/jpm_user_entitlements_details_original.txt +208 -0
  201. data/test/jpm_access_testfiles/jpm_user_entitlements_details_test.txt +7 -0
  202. data/test/madison535_testfiles/535madison_bldg_pass_2_Test.xlsx +0 -0
  203. data/test/madison535_testfiles/535madison_bldg_pass_Test.xlsx +0 -0
  204. data/test/mantis_testfiles/Mantis_AccessLevels_Test.xlsx +0 -0
  205. data/test/mantis_testfiles/Mantis_ActiveUsers_Rpt_Test.xlsx +0 -0
  206. data/test/sage100_testfiles/SY_UserReport_RolePreferencesDetails_Test.xlsx +0 -0
  207. data/test/sage100_testfiles/SY_UserReport_RoleTaskPermissionsDetails_Test.xlsx +0 -0
  208. data/test/som_testfiles/som_user_map_test.txt +7 -0
  209. data/test/som_testfiles/som_user_report_test.csv +25 -0
  210. data/test/stb_testfiles/STB_USERS_test.csv +24 -0
  211. data/test/stb_testfiles/STB_USERS_test_constant.csv +24 -0
  212. data/test/swift_online_testfiles/UserReport.xls +0 -0
  213. data/test/swift_online_testfiles/UserReport_Test.xlsx +0 -0
  214. data/test/swift_online_testfiles/test_outline_level.rb +7 -0
  215. data/test/t24_testfiles/T24_Grp_Rpt_Test.csv +7 -0
  216. data/test/t24_testfiles/T24_User_Rpt_Test.csv +7 -0
  217. data/test/test_ad_tracker.rb +148 -0
  218. data/test/test_aix_tracker.rb +71 -0
  219. data/test/test_alliance_swift_tracker.rb +131 -0
  220. data/test/test_audiolog_tracker.rb +23 -0
  221. data/test/test_check21_tracker.rb +30 -0
  222. data/test/test_citidirect_be_tracker.rb +110 -0
  223. data/test/test_citidirect_securities_tracker.rb +89 -0
  224. data/test/test_citrix_sharefile_tracker.rb +105 -0
  225. data/test/test_cmbrun_ny_tracker.rb +112 -0
  226. data/test/test_db_direct_tracker.rb +125 -0
  227. data/test/test_equinix_tracker.rb +119 -0
  228. data/test/test_fis_egifts_tracker.rb +105 -0
  229. data/test/test_fis_prime_tracker.rb +288 -0
  230. data/test/test_frb_tracker.rb +104 -0
  231. data/test/test_go_contact.rb +276 -0
  232. data/test/test_jpm_access_tracker.rb +122 -0
  233. data/test/test_madison535_tracker.rb +125 -0
  234. data/test/test_mantis_tracker.rb +133 -0
  235. data/test/test_sage100_tracker.rb +120 -0
  236. data/test/test_som_tracker.rb +71 -0
  237. data/test/test_stb_tracker.rb +120 -0
  238. data/test/test_swift_online_tracker.rb +116 -0
  239. data/test/test_t24_tracker.rb +151 -0
  240. data/test/test_utils.rb +46 -0
  241. data/test/test_vpn_tracker.rb +56 -0
  242. data/test/test_wms_tracker.rb +109 -0
  243. data/test/test_yst_tracker.rb +133 -0
  244. data/test/utils_testfiles/file2list_test.txt +13 -0
  245. data/test/utils_testfiles/load_know_user_map_testfile.txt +4 -0
  246. data/test/wms_testfiles/role_rpt_test.txt +6 -0
  247. data/test/wms_testfiles/user_rpt_test.txt +6 -0
  248. data/test/yst_testfiles/YiShiTong_Org_Test.csv +18 -0
  249. data/test/yst_testfiles/YiShiTong_User_Test.csv +5 -0
  250. data/ucert.gemspec +52 -0
  251. data/version.txt +12 -0
  252. metadata +410 -0
@@ -0,0 +1,19 @@
1
+ ##################################################
2
+ # Search the AD cache, filter out the DN obj by email first, then filter out the SAM account ID by DN
3
+ # Usage: ruby filter_email.rb [file_emails]
4
+ # file_emails contains a list of emails one entry per line
5
+
6
+ require "ucert"
7
+
8
+ k=Ucert::AdTracker.new(:verbose=>false)
9
+ File.open(ARGV[0],'r').each do |line|
10
+ #puts "Processing: #{line}"
11
+ email=line.chomp.strip
12
+ my_dn=k.ad_search_by_text(email,"person")
13
+ my_record=k.get_ad_record(my_dn)
14
+ my_id=k.get_sam_id(my_dn)
15
+ my_name=k.get_cn(my_dn)
16
+ my_department=k.get_department(my_dn)
17
+
18
+ puts my_id
19
+ end
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # ucert
4
+ #
5
+ # A Ruby library for enterprise user account certification / recertification / audit project
6
+ #
7
+ # Copyright (c) CMBNY Risk Department
8
+ #++
9
+
10
+ # A server side script designed to automatically update the 'cyber_idm' application's 'ad_users'
11
+ # and 'ad_computers' tables in a scheduled time-table
12
+ # Usage:
13
+ # => ruby idm_ad_reload.rb -h
14
+
15
+ require 'optparse'
16
+ require 'ostruct'
17
+ require "ucert"
18
+ require "sequel"
19
+ require "yaml"
20
+
21
+ class CmdOptions
22
+ # Returen an OpenStruct describing the command line options
23
+ def self.parse(args)
24
+ @options = OpenStruct.new # OpenStruct is a structure like hash table
25
+ @options.verbose = false # verbose and banner are key and value
26
+ @options.banner = "Usage: #{__FILE__} -h"
27
+ @version = ["0","1"] # Program version information
28
+ @last_change = "03/14/2016"
29
+ opt_parser = OptionParser.new do |opts|
30
+
31
+ # Boolean switch for the verbose mode switch
32
+ opts.on("-v", "--[no-]verbose", "Verbose Mode") do |v|
33
+ @options.verbose = v
34
+ end
35
+
36
+ # Command switch for configuration file
37
+ opts.on("-lYML", "--ldap=YML", "Ldap YML Configuration File") do |l|
38
+ @options.ldap = l
39
+ end
40
+
41
+ # Command switch for configuration file
42
+ opts.on("-dYML", "--db=YML", "Database YML Configuration File") do |d|
43
+ @options.db = d
44
+ end
45
+
46
+ # Displaying help.
47
+ opts.on("-h", "--help", "Display Help") do |v|
48
+ puts opts
49
+ exit
50
+ end
51
+
52
+ # Another typical switch to print the version.
53
+ opts.on_tail("-V","--version", String, "Show Program Version") do
54
+ @options.version = "Program Version: #{@version.join('.')}; Last Modification: #{@last_change}"
55
+ puts @options.version
56
+ exit
57
+ end
58
+ end
59
+ opt_parser.parse!(args)
60
+ puts "Captured Command Line Arguments: #{@options}" if @options.verbose
61
+ return @options
62
+ end
63
+ end
64
+
65
+ ##########################################################################
66
+ ### Main ###
67
+ ##########################################################################
68
+ # Command line arguments structure
69
+ @options=CmdOptions.parse(ARGV)
70
+
71
+ ldap_yml = @options.ldap || "/home/liyang138/cyber_idm/config/ldap.yml"
72
+ db_yml = @options.db || "/home/liyang138/cyber_idm/config/database.yml"
73
+
74
+ # Step 1 - Read the AD connecting db string from the 'cyber_idm' configuration file 'ldap.yml'
75
+ ldap_env = YAML.load_file(ldap_yml)[ENV['RAILS_ENV'] || 'development']
76
+ db_env = YAML.load_file(db_yml)[ENV['RAILS_ENV'] || 'development']
77
+
78
+ # Step 2 - Update the local cache database for AD
79
+ puts "Update AD local cache by using openldap connector ..."
80
+ ny_ad=Ucert::AdTracker.new(:verbose=>@options.verbose)
81
+ ny_ad.ldap_connector="openldap"
82
+ ny_ad.ldap_connector_id=ldap_env["admin_user"]
83
+ ny_ad.ldap_connector_pass=ldap_env["admin_password"]
84
+ ny_ad.update_ad_cache("person")
85
+ ny_ad.update_ad_cache("computer")
86
+ # reload
87
+ ny_ad.parse_openldap_cache("person")
88
+ ny_ad.parse_openldap_cache("computer")
89
+ puts "Done update AD cache."
90
+
91
+ # Step 3 - connect to the 'cyber_idm' DB
92
+ db = Sequel.connect(:adapter => db_env["adapter"], :user => db_env["username"], :password => db_env["password"], :host => db_env["host"] , :database => db_env["database"])
93
+
94
+ # Step 4 - Reload the 'ad_users' table
95
+ puts "\n\nReload ad_users table ..."
96
+ db[:ad_users].truncate
97
+ ad_user_table = db[:ad_users]
98
+ my_users = Hash.new
99
+ ny_ad.ad_person_records.keys.map do |my_dn|
100
+ my_sam_id=ny_ad.get_dn_attribute("person",my_dn,"sAMAccountName")
101
+ my_email=ny_ad.get_dn_attribute("person",my_dn,"mail")
102
+ my_name=ny_ad.get_cn(my_dn)
103
+ my_dept=ny_ad.get_dn_attribute("person",my_dn,"department")
104
+ my_acct_code=ny_ad.get_dn_attribute("person",my_dn,"userAccountControl")
105
+ my_acct_status=ny_ad.cntl_code_2_property_flag(my_acct_code)
106
+ my_workstations=ny_ad.get_dn_attribute("person",my_dn,"userWorkstations")
107
+ my_membership=ny_ad.get_dn_attributes("person",my_dn,"memberOf")
108
+ my_users[my_dn] = Hash.new
109
+ my_users[my_dn]['DN'] = my_dn
110
+ my_users[my_dn]['NAME'] = my_name
111
+ my_users[my_dn]['SAM'] = my_sam_id
112
+ my_users[my_dn]['EMAIL'] = my_email
113
+ my_users[my_dn]['DEPARTMENT'] = my_dept
114
+ my_users[my_dn]['ACCOUNT_STATUS'] = my_acct_status
115
+ my_users[my_dn]['WORKSTATION'] = my_workstations
116
+ my_users[my_dn]['MEMBERSHIP'] = my_membership
117
+ end
118
+ my_users.values.map do |record|
119
+ puts "Insert record into ad_users table: #{record}" if @verbose
120
+ if ad_user_table.insert(:dn => record['DN'].to_s, :name => record['NAME'].to_s, :sam => record['SAM'].to_s, :email => record['EMAIL'].to_s, :department => record['DEPARTMENT'].to_s, :account_status => record['ACCOUNT_STATUS'].to_s, :work_station_info => record['WORKSTATION'].to_s, :membership => record['MEMBERSHIP'].to_s)
121
+ puts "Success!" if @verbose
122
+ else
123
+ puts "Insert fail. " if @verbose
124
+ end
125
+ end
126
+ puts "Done reload ad_users."
127
+
128
+ # Step 5 - Reload the 'ad_computers' table
129
+ puts "\n\nReload ad_computers table ..."
130
+ db[:ad_computers].truncate
131
+ ad_computer_table = db[:ad_computers]
132
+ my_computers = Hash.new
133
+ ny_ad.ad_computer_records.keys.map do |my_dn|
134
+ my_sam_id=ny_ad.get_dn_attribute("computer",my_dn,"sAMAccountName")
135
+ my_os=ny_ad.get_os_info(my_dn)
136
+ my_host=ny_ad.get_dn_attribute("computer",my_dn,"dNSHostName")
137
+ if ny_ad.known_hosts.key?(my_host)
138
+ my_ip=ny_ad.known_hosts[my_host]
139
+ else
140
+ my_ip=ny_ad.nslookup(my_host)
141
+ ny_ad.known_hosts[my_host]=my_ip
142
+ end
143
+ my_created=ny_ad.get_dn_attribute("computer",my_dn,"whenCreated")
144
+ my_computers[my_dn] = Hash.new
145
+ my_computers[my_dn]['DN'] = my_dn
146
+ my_computers[my_dn]['SAM'] = my_sam_id
147
+ my_computers[my_dn]['OS'] = my_os
148
+ my_computers[my_dn]['HOST'] = my_host
149
+ my_computers[my_dn]['IP'] = my_ip
150
+ my_computers[my_dn]['CREATED'] = my_created
151
+ end
152
+ my_computers.values.map do |record|
153
+ puts "Insert record into ad_computers table: #{record}" if @verbose
154
+ if ad_computer_table.insert(:dn => record['DN'].to_s, :sam => record['SAM'].to_s, :os => record['OS'].to_s, :host => record['HOST'].to_s, :ip => record['IP'].to_s, :created => record['CREATED'].to_s)
155
+ puts "Success!" if @verbose
156
+ else
157
+ puts "Insert fail." if @berbose
158
+ end
159
+ end
160
+ puts "Done reload ad_computers."
161
+
162
+ # Step 6 - clean up
163
+ db.disconnect
164
+ ny_ad = nil
@@ -0,0 +1,82 @@
1
+ #--
2
+ # ucert
3
+ #
4
+ # A Ruby library for enterprise user account certification / recertification / audit project
5
+ #
6
+ # Copyright (c) CMBNY Risk Department
7
+ #++
8
+ require 'ucert/utils/utils'
9
+ require 'ucert/ad_tracker'
10
+ require 'ucert/t24_tracker'
11
+ require 'ucert/go_contact_tracker'
12
+ require 'ucert/fis_prime_tracker'
13
+ require 'ucert/fis_egifts_tracker'
14
+ require 'ucert/alliance_swift_tracker'
15
+ require 'ucert/citidirect_securities_tracker'
16
+ require 'ucert/jpm_access_tracker'
17
+ require 'ucert/db_direct_tracker'
18
+ require 'ucert/sage100_tracker'
19
+ require 'ucert/vpn_tracker'
20
+ require 'ucert/swift_online_tracker'
21
+ require 'ucert/check21_tracker'
22
+ require 'ucert/cmbrun_ny_tracker'
23
+ require 'ucert/mantis_tracker'
24
+ require 'ucert/audiolog_tracker'
25
+ require 'ucert/citidirect_be_tracker'
26
+ require 'ucert/stb_tracker'
27
+ require 'ucert/equinix_tracker'
28
+ require 'ucert/citrix_sharefile_tracker'
29
+ require 'ucert/aix_tracker'
30
+ require 'ucert/frb_tracker'
31
+ require 'ucert/wms_tracker'
32
+ require 'ucert/yst_tracker'
33
+ require 'ucert/madison535_tracker'
34
+ require 'ucert/bloomberg_tracker'
35
+ require 'ucert/cvm_tracker'
36
+ require 'ucert/som_tracker'
37
+ require 'ucert/adp_payroll_tracker'
38
+ require 'ucert/clear_par_tracker'
39
+
40
+ module Ucert
41
+
42
+ NAME = "Ucert"
43
+ GEM = "ucert"
44
+ VERSION = File.dirname(__FILE__) + "/../version.txt"
45
+ @verbose = false
46
+ # Module instance variable to keep track of the DN record change in the AD
47
+ @ad_delta = File.dirname(__FILE__) + "/../data/ad/ad_delta.txt"
48
+
49
+ class << self
50
+ attr_accessor :ad_delta, :verbose
51
+
52
+ # Simple parser for the project version file
53
+ def read_ver
54
+ ver=Hash.new
55
+ f=File.open(VERSION,'r')
56
+ f.each do |line|
57
+ line.chomp!
58
+ case line
59
+ when /^(\s)*#/
60
+ next
61
+ when /\=/
62
+ entry=line.split("=").map! {|x| x.strip}
63
+ ver[entry[0]]=entry[1]
64
+ end
65
+ end
66
+ f.close
67
+ return ver
68
+ end
69
+
70
+ def banner
71
+ ver=read_ver
72
+ art=""
73
+ string = "-"*80 + "\n" + art + "\n" + "Version: " + ver["version"] + "\tRelease Date: " + ver["date"] + "\nDesigned and developed by: " + ver["author"] + "\nEmail: " + ver["email"] + "\tLinkedIn: " + ver["linkedin"] + "\n" + "-"*80
74
+ end
75
+
76
+ # To do
77
+
78
+ private
79
+
80
+
81
+ end
82
+ end
@@ -0,0 +1,694 @@
1
+ #--
2
+ # ucert
3
+ #
4
+ # A Ruby library for enterprise user account certification / recertification / audit project
5
+ #
6
+ # Copyright (c) CMBNY Risk Department
7
+ #++
8
+ require "net/ldap"
9
+
10
+ # Class to handle the ative directory local data cache repository. Note this
11
+ # class depends on the 3rd party program 'openldap' @ www.openldap.org
12
+ class Ucert::AdTracker
13
+ include Ucert::Utils
14
+
15
+ attr_accessor :verbose,:ldap_connector,:ldapsearch_argv_1,:ldapsearch_argv_2,:ldap_connector_id, :ldap_connector_pass, \
16
+ :ldap_host, :ldap_port, :ldap_base, :ad_delta_map, :ad_delta, :refresh_dns_records
17
+ attr_reader :ad_person_records,:ad_computer_records, \
18
+ :ldapsearch_cache_person,:ldapsearch_cache_computer,:program_ldapsearch,:acct_cntl_code,:known_hosts
19
+
20
+ # Instance default variables
21
+ def initialize (params ={})
22
+ # Specify the dependency 3rd party application 'ldapsearch' installation path
23
+ @verbose=params.fetch(:verbose, false)
24
+ @refresh_dns_records=params.fetch(:refresh_dns_records, false) # params to turn on/off DNS records refreshment. Use with caution as it's time intensive task.
25
+ @program_ldapsearch = "/usr/bin/ldapsearch"
26
+ # Specify default ldap connector and connecting credential; currently we support: 1) 'openldap'
27
+ @ldap_connector = "openldap"
28
+ @ldap_connector_id=params.fetch(:ldap_connector_id,"")
29
+ @ldap_connector_pass=params.fetch(:ldap_connector_pass,"")
30
+ @ldap_host = params.fetch(:ldap_host, "CMBNY-OADC2.ny.cmbchina.com")
31
+ @ldap_port = params.fetch(:ldap_port, "389")
32
+ @ldap_base = params.fetch(:ldap_base, "DC=ny,DC=cmbchina,DC=com")
33
+ # Specify the dependency 3rd party application 'ldapsearh' command argument options
34
+ #@ldapsearch_argv_1 = " -b \"DC=ny,DC=cmbchina,DC=com\" -h CMBNY-OADC2.ny.cmbchina.com -p 389 -D "
35
+ @ldapsearch_argv_1 = " -b " + @ldap_base + " -h " + @ldap_host + " -p " + @ldap_port + " -D "
36
+ @ldapsearch_argv_2 = " -s sub \"objectcategory="
37
+ # Specify the cache file location for 'ldapsearch'
38
+ @ldapsearch_cache_person = File.dirname(__FILE__) + "/../../data/ad/ldap_person.txt"
39
+ @ldapsearch_cache_computer = File.dirname(__FILE__) + "/../../data/ad/ldap_computer.txt"
40
+ # Specify the local hosts cache file for fast DNS resolving
41
+ @hosts_cache = File.dirname(__FILE__) + "/../../data/ad/hosts"
42
+ @known_hosts=load_known_hosts(@hosts_cache)
43
+ # AD Delta detection
44
+ @ad_delta_map = File.dirname(__FILE__) + "/../../data/ad/ad_delta.txt"
45
+ @ad_delta = load_known_user_map_from_file (@ad_delta_map)
46
+ # class instance variables to keep track of the AD record changes
47
+ @ad_person_records = Hash.new
48
+ @ad_computer_records = Hash.new
49
+ # Refer to microsoft KB 'How to use the UserAccountControl flags' - https://support.microsoft.com/en-us/kb/305144
50
+ @acct_cntl_code={"SCRIPT"=>1, "ACCOUNTDISABLE"=>2, "HOMEDIR_REQUIRED"=>4, "LOCKOUT"=>5, "PASSWD_NOTREQD"=>6, \
51
+ "PASSWD_CANT_CHANGE"=>7, "ENCRYPTED_TEXT_PWD_ALLOWED"=>8, "TEMP_DUPLICATE_ACCOUNT"=>9, "NORMAL_ACCOUNT"=>10, \
52
+ "'INTERDOMAIN_TRUST_ACCOUNT'"=>12, "WORKSTATION_TRUST_ACCOUNT"=>13, "SERVER_TRUST_ACCOUNT"=>14, \
53
+ "DONT_EXPIRE_PASSWORD"=>17, "MNS_LOGON_ACCOUNT"=>18, "SMARTCARD_REQUIRED"=>19, \
54
+ "TRUSTED_FOR_DELEGATION"=>20, "NOT_DELEGATED"=>21, "USE_DES_KEY_ONLY"=>22, "DONT_REQ_PREAUTH"=>23, \
55
+ "PASSWORD_EXPIRED"=>24, "TRUSTED_TO_AUTH_FOR_DELEGATION"=>25, "PARTIAL_SECRETS_ACCOUNT"=>27}
56
+ # loading the instance variables
57
+ load_ad(@ldap_connector)
58
+ end
59
+
60
+ # Load AD tracker instance variables from the cache files; re-create the cache files if non-existing.
61
+ def load_ad (connector)
62
+ begin
63
+ case connector
64
+ when "openldap"
65
+ update_openldap_cache("person") unless File.exist?(@ldapsearch_cache_person)
66
+ parse_openldap_cache("person")
67
+ update_openldap_cache("computer") unless File.exist?(@ldapsearch_cache_computer)
68
+ parse_openldap_cache("computer")
69
+ else
70
+ #do nothing
71
+ end
72
+ rescue => ee
73
+ puts "Exception on method #{__method__}: #{ee}"
74
+ end
75
+ end
76
+
77
+ # wrapper to Net::LDAP ldap.bind method
78
+ def is_ldap_bind?
79
+ begin
80
+ ldap = Net::LDAP.new
81
+ ldap.host = @ldap_host
82
+ ldap.port = @ldap_port
83
+ ldap.auth @ldap_connector_id, @ldap_connector_pass
84
+ if ldap.bind
85
+ puts "LDAP bind to #{@ldap_host} successfully!"
86
+ return true
87
+ else
88
+ puts "LDAP bind to #{@ldap_host} fail!"
89
+ return false
90
+ end
91
+ rescue => ee
92
+ puts "Exception on method #{__method__}: #{ee}"
93
+ end
94
+ end
95
+
96
+ # method to update the active directory local cache file
97
+ def update_ad_cache (opt)
98
+ begin
99
+ puts "Start AD cache file update process for objectcategory: #{opt}"
100
+ case @ldap_connector
101
+ when "openldap"
102
+ my_dn=sid_2_dn(@ldap_connector_id)
103
+ abort "Error. Unknown user ID: #{@ldap_connector_id}" if my_dn.nil?
104
+ case opt
105
+ when "person"
106
+ # cmd = @program_ldapsearch + @ldapsearch_argv_1 + "\"" + my_dn + "\" -w " + @ldap_connector_pass + @ldapsearch_argv_2 + opt + "\" > " + @ldapsearch_cache_person
107
+ cmd = @program_ldapsearch + @ldapsearch_argv_1 + "\"" + @ldap_connector_id + "\" -w " + @ldap_connector_pass + @ldapsearch_argv_2 + opt + "\" > " + @ldapsearch_cache_person
108
+ when "computer"
109
+ # cmd = @program_ldapsearch + @ldapsearch_argv_1 + "\"" + my_dn + "\" -w " + @ldap_connector_pass + @ldapsearch_argv_2 + opt + "\" > " + @ldapsearch_cache_computer
110
+ cmd = @program_ldapsearch + @ldapsearch_argv_1 + "\"" + @ldap_connector_id + "\" -w " + @ldap_connector_pass + @ldapsearch_argv_2 + opt + "\" > " + @ldapsearch_cache_computer
111
+ else
112
+ raise "Error - unknown objectcategory: #{opt}"
113
+ end
114
+ else
115
+ raise "Error - unknown LDAP connector: #{@ldap_connector}"
116
+ end
117
+ # Test connection before the update
118
+ if is_ldap_bind?
119
+ puts "Execute shell command: #{cmd}" if @verbose
120
+ system(cmd)
121
+ puts "Done!"
122
+ end
123
+ sleep (2)
124
+ rescue => ee
125
+ puts "Exception on method #{__method__}: #{ee}"
126
+ end
127
+ end
128
+ alias_method :update, :update_ad_cache
129
+
130
+ # method to parse the openldap cache file, save the record into a hash data structure
131
+ def parse_openldap_cache (opt)
132
+ begin
133
+ case opt
134
+ when "person"
135
+ file = @ldapsearch_cache_person
136
+ when "computer"
137
+ file = @ldapsearch_cache_computer
138
+ else
139
+ raise "Unkown log file type: #{opt}"
140
+ end
141
+ puts "Start working on openldap log file: #{file}" if @verbose
142
+ raise "File not found. Please check your path again: #{file}" unless File.exist?(file)
143
+ f_cache = File.open(file, 'r:ISO-8859-1:UTF-8')
144
+ # recording bit to flag start / end of new ad record
145
+ recording=false
146
+ ad_objs=Hash.new
147
+ dn_key=String.new
148
+ # flag to check next line in file where the dn string may be split over to
149
+ dn_key_nextline_check=false
150
+ f_cache.each do |line|
151
+ line.chomp!
152
+ if dn_key_nextline_check
153
+ puts "Perform DN Key next line check for its completeness: #{dn_key}" if @verbose
154
+ if line =~ /^\s/
155
+ puts "Incomplete DN Key found: #{dn_key}" if @verbose
156
+ dn_key=dn_key+line.sub(/^\s/,'')
157
+ ad_objs[dn_key]=Array.new
158
+ dn_key_nextline_check=false
159
+ recording=true
160
+ next
161
+ else
162
+ puts "DN Key found completed: #{dn_key}" if @verbose
163
+ dn_key_nextline_check=false
164
+ ad_objs[dn_key]=Array.new
165
+ dn_key_nextline_check=false
166
+ recording=true
167
+ end
168
+ end
169
+ if line =~ /^dn\:/
170
+ puts "DN Key found in line: #{line}" if @verbose
171
+ dn_key=line.split(':')[1].sub(/^\s/,'')
172
+ puts "DN found: #{dn_key}" if @verbose
173
+ dn_key_nextline_check=true
174
+ next
175
+ end
176
+ if line.nil? or line.empty?
177
+ puts "Done processing one record." if @verbose
178
+ #sleep(2)
179
+ recording=false
180
+ next
181
+ end
182
+ if recording
183
+ puts "Start recording for record: #{dn_key}" if @verbose
184
+ if line=~ /^\s/
185
+ puts "Modify last attribute for its incompleteness: #{ad_objs[dn_key].last} - #{line} " if @verbose
186
+ ad_objs[dn_key][-1] = ad_objs[dn_key].last + line.sub(/^\s/,'')
187
+ else
188
+ puts "Adding new record attribute: #{line}" if @verbose
189
+ ad_objs[dn_key].push(line)
190
+ end
191
+ end
192
+ end
193
+ f_cache.close
194
+ case opt
195
+ when "person"
196
+ @ad_person_records=ad_objs
197
+ when "computer"
198
+ @ad_computer_records=ad_objs
199
+ save_hosts # refresh the hosts file
200
+ else
201
+ raise "Unkown log file type: #{opt}"
202
+ end
203
+ puts "Done processing the cache file: #{file}" if @verbose
204
+ rescue => ee
205
+ puts "Exception on method #{__method__}: #{ee}"
206
+ end
207
+ end
208
+
209
+ # generic text string search of ad local cache for matched record, return the record primary key, i.e. DN
210
+ def ad_search_by_text (keyword,opt="person")
211
+ begin
212
+ puts "Begin search on the cache for: #{keyword}" if @verbose
213
+ return nil if keyword.nil?
214
+ keywords=keyword.downcase.split(/(\,|\s|\;|\&|\!|\@|\#|\$|\%|\^|\*|\(|\)|\-|\=|\+|\=|\{|\}|\[|\]|\:|\~)/) \
215
+ - [" ", "", nil, ",", ";", "&", "!", "@", "#", "$", "%", "^", "*", "(", ")", "-", "+", "=", "{", "}", "[", "]", ":" "~"]
216
+ #txt.downcase!
217
+ case opt
218
+ when "computer"
219
+ @ad_computer_records.each do |key, val|
220
+ puts "Searching computer cache data." if @verbose
221
+ val.map do |entry|
222
+ every=entry.to_s.downcase
223
+ success=keywords.inject(true) {|found,word| break unless found; every.include?(word) && found; }
224
+ if success
225
+ return key
226
+ end
227
+ end
228
+ end
229
+ when "person"
230
+ @ad_person_records.each do |key, val|
231
+ puts "Searching person cache data." if @verbose
232
+ word_1=keywords.join(" ")
233
+ word_2=keywords.reverse.join(" ")
234
+ val.map do |entry|
235
+ puts "First order searching: #{entry} for #{word_1} or #{word_2}" if @verbose
236
+ every=entry.to_s.downcase
237
+ if every.include?(" " + word_1) or every.include?(" " + word_2)
238
+ puts "Best match found: #{entry}" if @verboseirb
239
+ return key
240
+ elsif every.include?(word_1) or every.include?(word_2)
241
+ puts "Best match found: #{entry}" if @verbose
242
+ return key
243
+ end
244
+ end
245
+ end
246
+ @ad_person_records.each do |key, val|
247
+ val.map do |entry|
248
+ puts "Secondary order searching: #{entry}" if @verbose
249
+ every=entry.to_s.downcase
250
+ success2=keywords.inject(true) {|found,word| break unless found; every.include?(word) && found; }
251
+ if success2
252
+ puts "Close match found: #{entry}" if @verbose
253
+ return key
254
+ end
255
+ end
256
+ end
257
+ else
258
+ raise "Unknow cache: #{opt}"
259
+ end
260
+ return nil
261
+ rescue => ee
262
+ puts "Exception on method #{__method__}: #{ee}"
263
+ end
264
+ end
265
+ alias_method :search, :ad_search_by_text
266
+
267
+ # generic text string search of ad local cache for matched records. Input is
268
+ # a keyword string, return the record primary keys, i.e. multiple DNs in an array.
269
+ def ad_searches_by_text (keyword,opt="person",max=10)
270
+ begin
271
+ puts "Begin searches on the cache for: #{keyword}" if @verbose
272
+ return nil if keyword.nil?
273
+ keywords=keyword.downcase.split(/(\,|\s|\;|\&|\!|\@|\#|\$|\%|\^|\*|\(|\)|\-|\=|\+|\=|\{|\}|\[|\]|\:|\~)/) \
274
+ - [" ", "", nil, ",", ";", "&", "!", "@", "#", "$", "%", "^", "*", "(", ")", "-", "+", "=", "{", "}", "[", "]", ":" "~"]
275
+ search_result=Array.new
276
+ case opt
277
+ when "computer"
278
+ cnt=0
279
+ @ad_computer_records.each do |key, val|
280
+ puts "Searching computer cache data on: #{key}" if @verbose
281
+ val.map do |entry|
282
+ break if cnt >= max # limit returned records to max
283
+ every = entry.to_s.downcase
284
+ success=keywords.inject(true) {|found,word| break unless found; every.include?(word) && found; }
285
+ if success
286
+ puts "Match found: #{entry}" if @verbose
287
+ search_result.push(key)
288
+ cnt+=1
289
+ break
290
+ end
291
+ end
292
+ end
293
+ when "person"
294
+ cnt=0
295
+ # Perform 1st order search of CN portion of DN only for the best match
296
+ @ad_person_records.keys.map do |x|
297
+ puts "Searching person DN entry for #{key}" if @verbose
298
+ word_1=keywords.join(" ").downcase
299
+ word_2=keywords.reverse.join(" ").downcase
300
+ y=get_cn(x).downcase
301
+ if y.include?(word_1) or y.include?(word_2)
302
+ puts "Match found: #{x}" if @verbose
303
+ search_result.push(x)
304
+ cnt+=1
305
+ end
306
+ end
307
+ # Perform 2nd order search of complete keyword string on person record attributes
308
+ @ad_person_records.each do |key, val|
309
+ puts "Searching person cache data on: #{key}" if @verbose
310
+ word_1=keywords.join(" ")
311
+ word_2=keywords.reverse.join(" ")
312
+ val.map do |entry|
313
+ break if cnt >= max # limit returned records to max
314
+ every = entry.to_s.downcase
315
+ if every.include?(word_1) or every.include?(word_2)
316
+ puts "Match found: #{entry}" if @verbose
317
+ search_result.push(key)
318
+ cnt+=1
319
+ break
320
+ end
321
+ end
322
+ end
323
+ # Perform 3rd order search of partial keyword string on the person record attributes
324
+ @ad_person_records.each do |key, val|
325
+ puts "Searching person cache data on: #{key}" if @verbose
326
+ val.map do |entry|
327
+ break if cnt >= max # limit returned records to max
328
+ every = entry.to_s.downcase
329
+ success=keywords.inject(true) {|found,word| break unless found; every.include?(word) && found; }
330
+ #entry_clean=entry.chomp
331
+ #if entry_clean.downcase.include?(txt)
332
+ if success
333
+ puts "Match found: #{entry}" if @verbose
334
+ search_result.push(key)
335
+ cnt+=1
336
+ break
337
+ end
338
+ end
339
+ end
340
+ #
341
+ else
342
+ raise "Unknow cache: #{opt}"
343
+ end
344
+ return search_result.uniq
345
+ rescue => ee
346
+ puts "Exception on method #{__method__}: #{ee}"
347
+ return search_result
348
+ end
349
+ end
350
+ alias_method :searches, :ad_searches_by_text
351
+
352
+ # Retrieve the specific dn object
353
+ def get_ad_record (dn)
354
+ begin
355
+ return @ad_person_records[dn] if @ad_person_records.key?(dn)
356
+ return @ad_computer_records[dn] if @ad_computer_records.key?(dn)
357
+ return "Unfound"
358
+ rescue => ee
359
+ puts "Exception on method #{__method__}: #{ee}"
360
+ return "Unfound"
361
+ end
362
+ end
363
+
364
+ # Retrieve the specific attribute from the dn's attribute collection
365
+ def get_dn_attribute (opt="person",dn,attr_name)
366
+ begin
367
+ case opt
368
+ when "person"
369
+ attrs=@ad_person_records[dn] if @ad_person_records.key?(dn)
370
+ when "computer"
371
+ attrs=@ad_computer_records[dn] if @ad_computer_records.key?(dn)
372
+ else
373
+ raise "Error - unknown objectcategory: #{opt}"
374
+ end
375
+ #puts attrs
376
+ attrs.map do |line|
377
+ (key,val)=line.chomp.split(':')
378
+ if key==attr_name
379
+ return val.strip
380
+ end
381
+ end
382
+ return nil
383
+ rescue => ee
384
+ puts "Exception on method #{__method__}: #{ee}"
385
+ return nil
386
+ end
387
+ end
388
+
389
+ # Retrieve the attributes from the dn's attribute collection; the output is the matchs inside an array
390
+ def get_dn_attributes (opt,dn,attr_name)
391
+ begin
392
+ founds = Array.new
393
+ case opt
394
+ when "person"
395
+ attrs=@ad_person_records[dn] if @ad_person_records.key?(dn)
396
+ when "computer"
397
+ attrs=@ad_computer_records[dn] if @ad_computer_records.key?(dn)
398
+ else
399
+ raise "Error - unknown objectcategory: #{opt}"
400
+ end
401
+ #puts attrs
402
+ attrs.map do |line|
403
+ (key,val)=line.chomp.split(':')
404
+ if key==attr_name
405
+ founds.push(val.strip)
406
+ end
407
+ end
408
+ return founds
409
+ rescue => ee
410
+ puts "Exception on method #{__method__}: #{ee}"
411
+ return nil
412
+ end
413
+ end
414
+
415
+ # Lookup DN by sAMAccountName attribute
416
+ def sid_2_dn (sid)
417
+ begin
418
+ @ad_person_records.keys.map do |dn|
419
+ attrs=@ad_person_records[dn]
420
+ attrs.map do |line|
421
+ (key,val)=line.chomp.split(':')
422
+ if val.strip.upcase==sid.strip.upcase
423
+ return dn
424
+ end
425
+ end
426
+ end
427
+ return nil
428
+ rescue => ee
429
+ puts "Exception on method #{__method__}: #{ee}"
430
+ return "Unfound"
431
+ end
432
+ end
433
+
434
+ # Retrieve the first CN "Full Name" for the DN
435
+ def get_cn (dn)
436
+ begin
437
+ attrs=@ad_person_records[dn] if @ad_person_records.key?(dn)
438
+ attrs=@ad_computer_records[dn] if @ad_computer_records.key?(dn)
439
+ attrs.map do |line|
440
+ (key,val)=line.chomp.split(':')
441
+ if key=="cn"
442
+ return val.strip
443
+ end
444
+ end
445
+ return "Unfound"
446
+ rescue => ee
447
+ puts "Exception on method #{__method__}: #{ee}"
448
+ return "Unfound"
449
+ end
450
+ end
451
+
452
+ # String manipulation to extract the first CN from the DN
453
+ def extract_first_cn (dn)
454
+ begin
455
+ return nil if dn.nil? or dn.empty?
456
+ dn.split(',').map do |x|
457
+ return x if x=~ /^cn=/i
458
+ end
459
+ rescue => ee
460
+ puts "Exception on method #{__method__}: #{ee}"
461
+ end
462
+ end
463
+
464
+ # Retrieve a list of CNs i.e. "Full Name" for the dns
465
+ def get_cns (dns)
466
+ begin
467
+ result=Array.new
468
+ dns.map do |dn|
469
+ cn=get_cn(dn)
470
+ result.push(cn)
471
+ end
472
+ return result
473
+ rescue => ee
474
+ puts "Exception on method #{__method__}: #{ee}"
475
+ return result
476
+ end
477
+ end
478
+
479
+ def get_os_info (dn)
480
+ begin
481
+ puts "Retrieve Operation System information for: #{dn}" if @verbose
482
+ os_info = String.new
483
+ attrs=@ad_computer_records[dn] if @ad_computer_records.key?(dn)
484
+ attrs.map do |line|
485
+ (key,val)=line.chomp.split(':')
486
+ case key
487
+ when "operatingSystem"
488
+ os_info += val.strip
489
+ when "operatingSystemVersion"
490
+ os_info += val
491
+ when "operatingSystemServicePack"
492
+ os_info += val
493
+ end
494
+ end
495
+ return os_info
496
+ rescue => ee
497
+ puts "Exception on method #{__method__}: #{ee}" if @verbose
498
+ return "Unfound"
499
+ end
500
+ end
501
+ alias_method :get_os, :get_os_info
502
+
503
+ # Convertion of MS UserAccountControl code in decimal value back to 'Property flag'
504
+ def cntl_code_2_property_flag (code)
505
+ begin
506
+ puts "Perform user account status lookup for user account control code: #{code}" if @verbose
507
+ code_2_status = Hash.new
508
+ @acct_cntl_code.each { |k,v| code_2_status[v]=k }
509
+ account_status = Array.new
510
+ b_code = code.to_i.to_s(2)
511
+ a_code = b_code.split('').reverse
512
+ (0...a_code.count).each do |x|
513
+ if a_code[x] === "1"
514
+ status = code_2_status[x+1]
515
+ account_status.push(status)
516
+ end
517
+ end
518
+ return account_status.join(' + ')
519
+ rescue => ee
520
+ puts "Exception on method #{__method__}: #{ee}" if @verbose
521
+ return "Unknown"
522
+ end
523
+ end
524
+ alias_method :code_2_flag, :cntl_code_2_property_flag
525
+
526
+ # Print out Adstore cache record in tab-delimited file format
527
+ def print (opt)
528
+ begin
529
+ puts "Print out the Active Directory Cache #{opt} record in tab-delimited format: " if @verbose
530
+ case opt
531
+ when "computer"
532
+ @ad_computer_records.keys.map do |my_dn|
533
+ my_sam_id=get_dn_attribute(opt,my_dn,"sAMAccountName")
534
+ my_os=get_os_info(my_dn)
535
+ my_host=get_dn_attribute(opt,my_dn,"dNSHostName")
536
+ my_membership=get_dn_attributes(opt,my_dn,"memberOf")
537
+ if @known_hosts.key?(my_host)
538
+ my_ip=@known_hosts[my_host]
539
+ else
540
+ my_ip=nslookup(my_host) if @refresh_dns_records
541
+ @known_hosts[my_host]=my_ip
542
+ end
543
+ my_created=get_dn_attribute(opt,my_dn,"whenCreated")
544
+ puts "#{my_dn}|#{my_sam_id}|#{my_os}|#{my_host}|#{my_ip}|#{my_created}|#{my_membership}"
545
+ end
546
+ # Save the known hosts into cache file for future reference
547
+ save_hosts(@hosts_cache)
548
+ when "person"
549
+ @ad_person_records.keys.map do |my_dn|
550
+ my_sam_id=get_dn_attribute(opt,my_dn,"sAMAccountName")
551
+ my_email=get_dn_attribute(opt,my_dn,"mail")
552
+ my_name=get_cn(my_dn)
553
+ my_dept=get_dn_attribute(opt,my_dn,"department")
554
+ my_acct_code=get_dn_attribute(opt,my_dn,"userAccountControl")
555
+ my_acct_status=cntl_code_2_property_flag(my_acct_code)
556
+ my_workstations=get_dn_attribute(opt,my_dn,"userWorkstations")
557
+ my_membership=get_dn_attributes(opt,my_dn,"memberOf")
558
+ puts "#{my_dn}|#{my_name}|#{my_sam_id}|#{my_email}|#{my_dept}|#{my_acct_status}|#{my_workstations}|#{my_membership}"
559
+ end
560
+ else
561
+ raise "Unknow cache table: #{opt} \t Please check your input Type again."
562
+ end
563
+ return nil
564
+ rescue => ee
565
+ puts "Exception on method #{__method__}: #{ee}"
566
+ end
567
+ end
568
+ alias_method :dump, :print # make the two method call the same function
569
+
570
+ # refresh @known_hosts instance based on the lastest ad_computer_records
571
+ def refresh_hosts
572
+ begin
573
+ @ad_computer_records.keys.map do |my_dn|
574
+ my_sam_id=get_dn_attribute("computer",my_dn,"sAMAccountName")
575
+ my_os=get_os_info(my_dn)
576
+ my_host=get_dn_attribute("computer",my_dn,"dNSHostName")
577
+ my_membership=get_dn_attributes("computer",my_dn,"memberOf")
578
+ if @known_hosts.key?(my_host)
579
+ my_ip=@known_hosts[my_host]
580
+ else
581
+ my_ip=nslookup(my_host)
582
+ @known_hosts[my_host]=my_ip
583
+ end
584
+ end
585
+ rescue => ee
586
+ puts "Exception on method #{__method__}: #{ee}"
587
+ end
588
+ end
589
+
590
+ # Save the known hosts table into cache file
591
+ def save_hosts(f_hosts=@hosts_cache)
592
+ begin
593
+ puts "Save the hosts table from memory to file: #{f_hosts} ..." if @verbose
594
+ # update the @known_hosts instance
595
+ refresh_hosts if @refresh_dns_records
596
+ # Write the @known_hosts instance back to hosts file
597
+ timestamp=Time.now
598
+ f=File.open(f_hosts, 'w')
599
+ f.write "# local hosts file created by the #{self.class} class #{__method__} method at: #{timestamp}"
600
+ (@known_hosts.keys-[nil]).sort.map do |key|
601
+ unless key =~ /\d+\.\d+\.\d+\.\d+/
602
+ f.write "\n#{key}\t#{@known_hosts[key]}"
603
+ end
604
+ end
605
+ f.close
606
+ puts "local host repository is successfully saved to: #{f_hosts}" if @verbose
607
+ rescue => ee
608
+ puts "Exception on method #{__method__}: #{ee}"
609
+ end
610
+ end
611
+
612
+ # Save the AD change back into cache file
613
+ def save_delta (f_delta=@ad_delta_map)
614
+ begin
615
+ puts "Save the AD Delta table from memory to file: #{f_delta} ..." if @verbose
616
+ timestamp=Time.now
617
+ f=File.open(f_delta, 'w')
618
+ f.write "# AD Delta created by the #{self.class} class #{__method__} method at: #{timestamp}"
619
+ @ad_delta.each do |key, value|
620
+ unless key =~ /\d+\.\d+\.\d+\.\d+/ or key.nil?
621
+ f.write "\n#{key}|#{value}"
622
+ end
623
+ end
624
+ f.close
625
+ puts "AD delta records are successfully saved to: #{f_hosts}" if @verbose
626
+ rescue => ee
627
+ puts "Exception on method #{__method__}: #{ee}"
628
+ end
629
+ end
630
+
631
+ # Load the hosts cache file for fast DNS resolving
632
+ def load_known_hosts (f_hosts=@file_hosts)
633
+ puts "Loading local hosts from file: #{f_hosts} ..." if @verbose
634
+ begin
635
+ known_hosts=Hash.new
636
+ f=File.open(f_hosts, 'r')
637
+ f.each do |line|
638
+ next unless line =~ /\d+\.\d+\.\d+\.\d+/
639
+ entry=line.chomp.split(%r{\t+|\s+|\,})
640
+ key=entry[0].downcase
641
+ value=entry[1]
642
+ puts "Loading value pair: #{key} - #{value}" if @verbose
643
+ known_hosts[key] = Hash.new unless known_hosts.key?(key)
644
+ known_hosts[key]= value
645
+ end
646
+ f.close
647
+ return known_hosts
648
+ rescue => ee
649
+ puts "Exception on method #{__method__}: #{ee}"
650
+ return Hash.new
651
+ end
652
+ end
653
+
654
+ # Local DNS reverse lookup
655
+ def local_ip_2_host (ip)
656
+ puts "Perform local IP to hostname lookup on IP: #{ip}" if @verbose
657
+ begin
658
+ ip.chomp!
659
+ raise "Invalid IP address format: #{ip}" unless ip =~ /\d+\.\d+\.\d+\.\d+/
660
+ @known_hosts.to_a.reverse.to_h.each do |key,val|
661
+ return key.to_s if val == ip
662
+ end
663
+ return nil
664
+ rescue => ee
665
+ puts "Exception on method #{__method__}: #{ee}"
666
+ return nil
667
+ end
668
+ end
669
+
670
+ # SAM ID to DN reverse lookup
671
+ def sam_2_dn (id)
672
+ puts "Perform SAM ID to DN lookup for: #{id}" if @verbose
673
+ begin
674
+ id.strip!
675
+ @ad_person_records.keys.map do |my_dn|
676
+ sam_id=get_dn_attribute("person",my_dn,"sAMAccountName")
677
+ if sam_id == id
678
+ return my_dn
679
+ end
680
+ end
681
+ @ad_computer_records.keys.map do |my_dn|
682
+ sam_id=get_dn_attribute("computer",my_dn,"sAMAccountName")
683
+ if sam_id == id
684
+ return my_dn
685
+ end
686
+ end
687
+ return nil
688
+ rescue => ee
689
+ puts "Exception on method #{__method__}: #{ee}"
690
+ return nil
691
+ end
692
+ end
693
+
694
+ end