racf 0.6.0

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.
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