racf 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +8 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +18 -0
  4. data/Gemfile +14 -0
  5. data/Gemfile.lock +40 -0
  6. data/README.rdoc +56 -0
  7. data/Rakefile +9 -0
  8. data/TODO.txt +5 -0
  9. data/config/racf.yml.sample +27 -0
  10. data/lib/racf.rb +78 -0
  11. data/lib/racf/client.rb +138 -0
  12. data/lib/racf/commands/abstract_command.rb +13 -0
  13. data/lib/racf/commands/listgrp.rb +189 -0
  14. data/lib/racf/commands/listgrp/group_members_parser.rb +104 -0
  15. data/lib/racf/commands/listuser.rb +112 -0
  16. data/lib/racf/commands/rlist.rb +208 -0
  17. data/lib/racf/commands/search.rb +31 -0
  18. data/lib/racf/pagers/cached_ispf_pager.rb +91 -0
  19. data/lib/racf/pagers/ispf_pager.rb +57 -0
  20. data/lib/racf/s3270.rb +136 -0
  21. data/lib/racf/session.rb +149 -0
  22. data/lib/racf/version.rb +3 -0
  23. data/racf.gemspec +16 -0
  24. data/script/ci +3 -0
  25. data/spec/fixtures/config/racf.yml +9 -0
  26. data/spec/fixtures/listgrp/multiple_groups_multiple_members.txt +26 -0
  27. data/spec/fixtures/listgrp/multiple_members.txt +10 -0
  28. data/spec/fixtures/listgrp/no_members.txt +4 -0
  29. data/spec/fixtures/listgrp/not_found_groups.txt +21 -0
  30. data/spec/fixtures/listgrp/one_group.txt +7 -0
  31. data/spec/fixtures/listgrp/one_group_with_members.txt +13 -0
  32. data/spec/fixtures/listgrp/one_member.txt +7 -0
  33. data/spec/fixtures/listuser/all_users.txt +45 -0
  34. data/spec/fixtures/listuser/just_users_not_found.txt +3 -0
  35. data/spec/fixtures/listuser/one_user.txt +47 -0
  36. data/spec/fixtures/listuser/some_not_found_users.txt +88 -0
  37. data/spec/fixtures/racf_cache_dump.yml +9 -0
  38. data/spec/fixtures/rlist/gims.txt +135 -0
  39. data/spec/fixtures/rlist/gims_with_no_tims.txt +135 -0
  40. data/spec/fixtures/rlist/gims_with_not_found.txt +89 -0
  41. data/spec/fixtures/rlist/just_one_not_found.txt +1 -0
  42. data/spec/fixtures/rlist/multiple_not_found.txt +3 -0
  43. data/spec/fixtures/rlist/rlist_success.txt +50 -0
  44. data/spec/fixtures/rlist/tims_without_users.txt +119 -0
  45. data/spec/fixtures/search/gims.txt +30 -0
  46. data/spec/fixtures/search/tims.txt +30 -0
  47. data/spec/fixtures/session/screen_with_bottom_menu.txt +31 -0
  48. data/spec/fixtures/session/screen_with_top_and_bottom_menu.txt +47 -0
  49. data/spec/fixtures/session/screen_with_top_menu.txt +29 -0
  50. data/spec/fixtures/session/screen_without_menu.txt +13 -0
  51. data/spec/racf/client_spec.rb +155 -0
  52. data/spec/racf/commands/listgrp/group_members_parser_spec.rb +82 -0
  53. data/spec/racf/commands/listgrp_spec.rb +303 -0
  54. data/spec/racf/commands/listuser_spec.rb +123 -0
  55. data/spec/racf/commands/rlist_spec.rb +257 -0
  56. data/spec/racf/commands/search_spec.rb +66 -0
  57. data/spec/racf/pagers/cached_ispf_pager_spec.rb +212 -0
  58. data/spec/racf/pagers/ispf_pager_spec.rb +59 -0
  59. data/spec/racf/session_spec.rb +114 -0
  60. data/spec/racf_spec.rb +106 -0
  61. data/spec/spec_helper.rb +18 -0
  62. data/spec/support/helpers.rb +5 -0
  63. metadata +162 -0
@@ -0,0 +1,104 @@
1
+ require 'racf/commands/abstract_command'
2
+
3
+ require 'state_machine'
4
+
5
+ module Racf
6
+ module Commands
7
+ class Listgrp < AbstractCommand
8
+ class GroupMembersParser
9
+ attr_reader :members
10
+
11
+ state_machine :state, :initial => :nothing_processed do
12
+ state :nothing_processed, :headers_processed, :first_line_processed,
13
+ :second_line_processed, :no_members
14
+
15
+ state :member_processed, :no_members do
16
+ def parsed?
17
+ true
18
+ end
19
+ end
20
+
21
+ state all - [:member_processed, :no_members] do
22
+ def parsed?
23
+ false
24
+ end
25
+ end
26
+
27
+ event :process_first_line do
28
+ transition [:headers_processed, :member_processed] => :first_line_processed
29
+ end
30
+
31
+ event :process_second_line do
32
+ transition :first_line_processed => :second_line_processed
33
+ end
34
+
35
+ event :process_third_line do
36
+ transition :second_line_processed => :member_processed
37
+ end
38
+ end
39
+
40
+ def initialize
41
+ @current_line = nil
42
+ @members = {}
43
+ @current_member = nil
44
+
45
+ super
46
+ end
47
+
48
+ def parse(line)
49
+ @current_line = line.strip
50
+
51
+ case state_name
52
+ when :nothing_processed
53
+ process_headers
54
+ when :headers_processed, :member_processed
55
+ process_first_line
56
+ when :first_line_processed
57
+ process_second_line
58
+ when :second_line_processed
59
+ process_third_line
60
+ end
61
+ end
62
+
63
+
64
+ private
65
+ def process_headers
66
+ members_header = /USER\(S\)=\s+ACCESS=\s+ACCESS COUNT=\s+UNIVERSAL ACCESS=/
67
+
68
+ if @current_line.match(members_header)
69
+ @state = "headers_processed"
70
+ elsif @current_line == "NO USERS"
71
+ @state = "no_members"
72
+ end
73
+ end
74
+
75
+ def process_first_line
76
+ member, access, access_count, universal_access = @current_line.split(' ')
77
+ @current_member = member
78
+ @members[@current_member] = {
79
+ :access => access,
80
+ :access_count => access_count,
81
+ :universal_access => universal_access
82
+ }
83
+
84
+ super
85
+ end
86
+
87
+ def process_second_line
88
+ connect_attributes = @current_line.match(/CONNECT ATTRIBUTES=(.*?)$/)[1]
89
+ @members[@current_member].merge!(:connect_attributes => connect_attributes)
90
+
91
+ super
92
+ end
93
+
94
+ def process_third_line
95
+ revoke_date, resume_date = @current_line.match(/REVOKE DATE=(.*?)\s+RESUME DATE=(.*?)$/)[1..-1]
96
+ @members[@current_member].merge!(:revoke_date => revoke_date)
97
+ @members[@current_member].merge!(:resume_date => resume_date)
98
+
99
+ super
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,112 @@
1
+ require 'strscan'
2
+ require 'state_machine'
3
+ require 'racf/commands/abstract_command'
4
+
5
+
6
+ module Racf
7
+ module Commands
8
+ class Listuser < AbstractCommand
9
+ state_machine :state, :initial => :nothing_processed do
10
+ state :nothing_processed, :name_processed, :user_processed
11
+
12
+ event :process_name do
13
+ transition [:nothing_processed, :user_processed] => :name_processed
14
+ end
15
+
16
+ event :finish_user_parsing do
17
+ transition :name_processed => :user_processed
18
+ end
19
+ end
20
+
21
+ def initialize(session)
22
+ @users = {}
23
+ @current_user = {}
24
+
25
+ super
26
+ end
27
+
28
+ def run(*args)
29
+ users_ids = extract_users_ids(args)
30
+ command = "LISTUSER (#{users_ids})"
31
+ raw_output = @session.run_command(command)
32
+
33
+ @scanner = StringScanner.new(raw_output)
34
+
35
+ log_number_of_users(@scanner.rest)
36
+
37
+ @user_index = 1
38
+ while @scanner.scan(/(.*?)$\n/)
39
+ case state_name
40
+ when :nothing_processed, :user_processed
41
+ process_name
42
+ when :name_processed
43
+ finish_user_parsing
44
+ end
45
+ end
46
+
47
+ users = @users
48
+ clear_state
49
+
50
+ users
51
+ end
52
+
53
+ def extract_resources(arguments)
54
+ resources = arguments.first
55
+
56
+ case resources
57
+ when String
58
+ [resources]
59
+ when Array
60
+ resources
61
+ end
62
+ end
63
+
64
+ private
65
+ def extract_users_ids(arguments)
66
+ extract_resources(arguments).join(" ")
67
+ end
68
+
69
+ def log_number_of_users(users_output)
70
+ @number_of_users = users_output.scan(/USER=.*?NAME=.*?/).size
71
+ Racf.logger.info("Processing #{@number_of_users} users")
72
+ end
73
+
74
+ def current_line
75
+ @scanner.matched
76
+ end
77
+
78
+ def process_name
79
+ if matched_data = current_line.strip.match(/USER=(.*?)\s+NAME=(.*?)\s+OWNER/)
80
+ Racf.logger.info("Processing user #{@user_index} of #{@number_of_users} users")
81
+
82
+ @current_user = {}
83
+ @current_user[:name] = matched_data[2]
84
+ user_id = matched_data[1]
85
+ @users[user_id.to_sym] = @current_user
86
+
87
+ Racf.logger.info("\tProcessing user #{user_id}")
88
+
89
+ super
90
+ end
91
+ end
92
+
93
+ def finish_user_parsing
94
+ while @scanner.scan(/(.*?)$\n/)
95
+ if current_line.strip =~ /USER=(.*?)\s+NAME=(.*?)\s+OWNER/
96
+ @scanner.unscan
97
+ break
98
+ end
99
+ end
100
+
101
+ @current_user = {}
102
+ @user_index += 1
103
+ super
104
+ end
105
+
106
+ def clear_state
107
+ @users = {}
108
+ @current_user = {}
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,208 @@
1
+ require 'strscan'
2
+ require 'state_machine'
3
+ require 'racf/commands/abstract_command'
4
+
5
+ module Racf
6
+ module Commands
7
+
8
+ class Rlist < AbstractCommand
9
+ NAME_HEADER = /CLASS\s+NAME/
10
+ NO_USERS = /NO\s+USERS\s+IN\s+ACCESS\s+LIST/
11
+ OWNER_HEADER = /LEVEL\s+OWNER\s+UNIVERSAL\s+ACCESS\s+YOUR\s+ACCESS\s+WARNING/
12
+ CONDITIONAL_ACCESS_LIST_HEADER = /ID\s+ACCESS\s+ACCESS\s+COUNT\s+CLASS\s+ENTITY\s+NAME/
13
+
14
+ state_machine :state, :initial => :nothing_processed do
15
+ state :nothing_processed, :name_processed, :members_processed,
16
+ :owner_processed, :users_processed, :resource_processed
17
+
18
+ event :process_name do
19
+ transition [:nothing_processed, :resource_processed] => :name_processed
20
+ end
21
+
22
+ event :process_members do
23
+ transition :name_processed => :members_processed
24
+ end
25
+
26
+ event :process_owner do
27
+ transition [:name_processed, :members_processed] => :owner_processed
28
+ end
29
+
30
+ event :process_users do
31
+ transition :owner_processed => :users_processed
32
+ end
33
+
34
+ event :finish_resource_processing do
35
+ transition :users_processed => :resource_processed
36
+ end
37
+ end
38
+
39
+ def initialize(session)
40
+ @resources = {}
41
+ @current_resource = {}
42
+
43
+ super
44
+ end
45
+
46
+ def run(*args)
47
+ class_name = args[0]
48
+ resources_names = extract_resources_names(args)
49
+ command = "RLIST #{class_name} (#{resources_names}) AUTHUSER"
50
+
51
+ raw_output = @session.run_command(command)
52
+
53
+ @scanner = StringScanner.new(raw_output)
54
+ log_number_of_resources(args[1])
55
+
56
+ while @scanner.scan(/(.*?)$\n/)
57
+ case state_name
58
+ when :nothing_processed, :resource_processed
59
+ process_name
60
+ when :name_processed
61
+ case class_name
62
+ when "TIMS"
63
+ process_owner
64
+ when "GIMS"
65
+ process_members
66
+ end
67
+ when :members_processed
68
+ process_owner
69
+ when :owner_processed
70
+ process_users
71
+ when :users_processed
72
+ finish_resource_processing
73
+ end
74
+ end
75
+
76
+ resources = @resources
77
+ clear_state
78
+
79
+ resources
80
+ end
81
+
82
+ def extract_resources(args)
83
+ resources = args[1]
84
+
85
+ case resources
86
+ when String
87
+ [resources]
88
+ when Array
89
+ resources
90
+ end
91
+ end
92
+
93
+ private
94
+ def extract_resources_names(arguments)
95
+ extract_resources(arguments).join(" ")
96
+ end
97
+
98
+ def log_number_of_resources(resources)
99
+ case resources
100
+ when String
101
+ Racf.logger.info("Processing #{resources} resources")
102
+ when Array
103
+ Racf.logger.info("Processing #{resources.size} resources")
104
+ end
105
+ end
106
+
107
+ def current_line
108
+ @scanner.matched
109
+ end
110
+
111
+ def skip_lines(number_of_lines)
112
+ number_of_lines.times { @scanner.scan(/(.*?)$\n/) }
113
+ end
114
+
115
+ def process_name
116
+ if current_line.strip.match(NAME_HEADER)
117
+ skip_lines(2)
118
+ matched_data = current_line.strip.match(/.*?\s+(.*?)$/)
119
+
120
+ resource_name = matched_data[1]
121
+ @resources.merge!({ resource_name.to_sym => @current_resource })
122
+
123
+ super
124
+ end
125
+ end
126
+
127
+ def process_members
128
+ @current_resource[:tims] = []
129
+
130
+ if current_line.strip.match(/RESOURCES\s+IN\s+GROUP/)
131
+ skip_lines(1)
132
+
133
+ while @scanner.scan(/(.*?)$\n/)
134
+ break if current_line.strip.match(OWNER_HEADER) || current_line.strip.match(/NONE/)
135
+
136
+ matched_data = current_line.strip.match(/^(.*)$/)
137
+ @current_resource[:tims] << matched_data[1]
138
+ end
139
+
140
+ @scanner.unscan
141
+
142
+ @current_resource[:tims].map!(&:strip)
143
+ @current_resource[:tims] = @current_resource[:tims].find_all { |tim| !tim.empty? }
144
+ super
145
+ end
146
+ end
147
+
148
+ def process_owner
149
+ if current_line.strip.match(OWNER_HEADER)
150
+ skip_lines(2)
151
+ matched_data = current_line.strip.match(/.*?\s+(.*?)\s+.*$/)
152
+ @current_resource[:owner] = matched_data[1]
153
+
154
+ super
155
+ end
156
+ end
157
+
158
+ def process_users
159
+ @current_resource[:standard_access_list] = []
160
+
161
+ if current_line.strip.match(/USER\s+ACCESS\s+ACCESS\s+COUNT/)
162
+ skip_lines(1)
163
+ process_access_list
164
+
165
+ super
166
+ end
167
+ end
168
+
169
+ def process_access_list
170
+ while @scanner.scan(/(.*?)$\n/)
171
+ break if current_line.strip.empty? ||
172
+ current_line.strip.match(NO_USERS) ||
173
+ current_line.strip.match(CONDITIONAL_ACCESS_LIST_HEADER)
174
+
175
+ matched_data = current_line.strip.match(/(.*?)\s+(.*?)\s+.*?$/)
176
+ user = {
177
+ :user_or_group => matched_data[1],
178
+ :authority_level => matched_data[2]
179
+ }
180
+
181
+ @current_resource[:standard_access_list] << user
182
+ end
183
+ end
184
+
185
+ def finish_resource_processing
186
+ while @scanner.scan(/(.*?)$\n/)
187
+ if current_line.nil?
188
+ break
189
+ elsif current_line.strip.match(NAME_HEADER)
190
+ @scanner.unscan
191
+ break
192
+ end
193
+ end
194
+
195
+ @current_resource = {}
196
+
197
+ super
198
+ end
199
+
200
+ def clear_state
201
+ @resources = {}
202
+ @current_resource = {}
203
+ end
204
+
205
+ end
206
+
207
+ end
208
+ end
@@ -0,0 +1,31 @@
1
+ require 'racf/commands/abstract_command'
2
+
3
+ module Racf
4
+ module Commands
5
+ class Search < AbstractCommand
6
+ # ATENTION: That method deals only with the SEARCH CLASS(TIMS)
7
+ # and SEARCH CLASS(GIMS) queries
8
+ #
9
+ def run(*args)
10
+ begin
11
+ command = "SEARCH #{args.first}"
12
+ response = @session.run_command(command)
13
+
14
+ profiles = []
15
+ response.each_line.each do |line|
16
+ profiles << line.strip
17
+ end
18
+
19
+ return profiles
20
+ rescue StandardError => e
21
+ error_traces = "\t" + e.message + "\n\t" + e.backtrace.join("\n\t")
22
+ Racf.logger.info("Ooops, an exception was raised!\n#{error_traces}")
23
+ end
24
+ end
25
+
26
+ def extract_resources(arguments)
27
+ []
28
+ end
29
+ end
30
+ end
31
+ end