Module: ALGOSEC_SDK::BusinessFlowHelper
- Included in:
- Client
- Defined in:
- lib/algosec-sdk/helpers/business_flow_helper.rb
Overview
Contains helper methods for BusinessFlow
Instance Method Summary collapse
-
#apply_application_draft(app_revision_id) ⇒ Object
Apply application draft.
-
#create_application_flow(app_revision_id, flow_name, sources, destinations, network_services, network_users, network_apps, comment, type = 'APPLICATION', custom_fields = []) ⇒ Object
Create a flow rubocop:disable Metrics/ParameterLists.
-
#create_missing_network_objects(network_object_names) ⇒ Object
Create all the missing network objects which are simple IPv4 ip or subnet.
-
#create_missing_services(service_names) ⇒ Object
Create all the missing network services which are of simple protocol/port pattern.
-
#create_network_object(type, content, name) ⇒ Object
Create a new network object.
-
#create_network_service(service_name, content) ⇒ Object
Create a new network service.
-
#define_application_flows(app_name, new_app_flows) ⇒ Object
Update application flows of an application to match a requested flows configuration.
-
#delete_flow_by_id(app_revision_id, flow_id) ⇒ Object
Delete a specific flow.
-
#get_app_revision_id_by_name(app_name) ⇒ Boolean
Get latest application revision id by application name.
-
#get_application_flow_by_name(app_revision_id, flow_name) ⇒ Object
Fetch an application flow by it’s name.
-
#get_application_flows(app_revision_id) ⇒ Array<Hash>
Get list of application flows for an application revision id.
-
#get_application_flows_hash(app_revision_id) ⇒ Hash
Get application flows from the server as a hash from flow name it it’s content.
-
#get_flow_connectivity(app_revision_id, flow_id) ⇒ String
Get connectivity status for a flow.
-
#implement_app_flows_plan(app_name, new_app_flows, flows_from_server, flows_to_delete, flows_to_create, flows_to_modify) ⇒ Object
Create/modify/delete application2 flows to match a given flow plan returned by ‘plan_application_flows’ param [Array<String>] flows_to_modify List of network flow names to delete and re-create with the new definition.
-
#login ⇒ Array<Hash>
Request login to get session cookie credentials.
-
#plan_application_flows(server_app_flows, new_app_flows) ⇒ Object
Return a plan for modifying application flows based on current and newly proposed application flows definition.
-
#search_network_object(ip_or_subnet, search_type) ⇒ Object
Search a network object.
Instance Method Details
#apply_application_draft(app_revision_id) ⇒ Object
Apply application draft
155 156 157 158 159 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 155 def apply_application_draft(app_revision_id) response = rest_post("/BusinessFlow/rest/v1/applications/#{app_revision_id}/apply") response_handler(response) true end |
#create_application_flow(app_revision_id, flow_name, sources, destinations, network_services, network_users, network_apps, comment, type = 'APPLICATION', custom_fields = []) ⇒ Object
Create a flow rubocop:disable Metrics/ParameterLists
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 85 def create_application_flow( app_revision_id, flow_name, sources, destinations, network_services, network_users, network_apps, comment, type = 'APPLICATION', custom_fields = [] ) # rubocop:enable Metrics/ParameterLists # Create the missing network objects from the sources and destinations create_missing_network_objects(sources + destinations) create_missing_services(network_services) get_named_objects = ->(name_list) { name_list.map { |name| { name: name } } } new_flow = { name: flow_name, sources: get_named_objects.call(sources), destinations: get_named_objects.call(destinations), users: network_users, network_applications: get_named_objects.call(network_apps), services: get_named_objects.call(network_services), comment: comment, type: type, custom_fields: custom_fields } response = rest_post("/BusinessFlow/rest/v1/applications/#{app_revision_id}/flows/new", body: [new_flow]) flows = response_handler(response) # AlgoSec return a list of created flows, we created only one flows[0] end |
#create_missing_network_objects(network_object_names) ⇒ Object
Create all the missing network objects which are simple IPv4 ip or subnet
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 305 def create_missing_network_objects(network_object_names) # TODO: Add unitests that objects are being create only once (if the same object is twice in the incoming list) network_object_names = Set.new(network_object_names) ipv4_or_subnet_objects = network_object_names.map do |object_name| begin IPAddress.parse object_name search_result = search_network_object(object_name, NetworkObjectSearchType::EXACT) # If no object was found in search, we'll count this object for creation search_result.empty? ? object_name : nil rescue ArgumentError # The parsed object name was not IP Address or IP Subnet, ignore it nil end end.compact # Create all the objects. If the error from the server tells us that the object already exists, ignore the error ipv4_or_subnet_objects.map do |ipv4_or_subnet| create_network_object(NetworkObjectType::HOST, ipv4_or_subnet, ipv4_or_subnet) end.compact end |
#create_missing_services(service_names) ⇒ Object
Create all the missing network services which are of simple protocol/port pattern
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 330 def create_missing_services(service_names) parsed_services = service_names.map do |service_name| protocol, port = service_name.scan(%r{(TCP|UDP)/(\d+)}i).last [service_name, [protocol, port]] if !protocol.nil? && !port.nil? end.compact # Create all the objects. If the error from the server tells us that the object already exists, ignore the error parsed_services.map do |parsed_service| service_name, service_content = parsed_service begin create_network_service(service_name, [service_content]) rescue StandardError => e # If the error is different from "service already exists", the exception will be re-raised raise e if e.to_s.index('Service name already exists').nil? end end.compact end |
#create_network_object(type, content, name) ⇒ Object
Create a new network object
180 181 182 183 184 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 180 def create_network_object(type, content, name) new_object = { type: type, name: name, content: content } response = rest_post('/BusinessFlow/rest/v1/network_objects/new', body: new_object) response_handler(response) end |
#create_network_service(service_name, content) ⇒ Object
Create a new network service
166 167 168 169 170 171 172 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 166 def create_network_service(service_name, content) content = content.map { |service| { protocol: service[0], port: service[1] } } new_service = { name: service_name, content: content } response = rest_post('/BusinessFlow/rest/v1/network_services/new', body: new_service) response_handler(response) true end |
#define_application_flows(app_name, new_app_flows) ⇒ Object
Update application flows of an application to match a requested flows configuration.
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 282 def define_application_flows(app_name, new_app_flows) flows_from_server = get_application_flows_hash(get_app_revision_id_by_name(app_name)) flows_to_delete, flows_to_create, flows_to_modify = plan_application_flows(flows_from_server, new_app_flows) implement_app_flows_plan( app_name, new_app_flows, flows_from_server, flows_to_delete, flows_to_create, flows_to_modify ) # Stage 2: Run connectivity check for all the unchanged flows. Check with Chef is this non-deterministic approach # is OK with them for the cookbook. # # Return the current list of created flows if successful get_application_flows(get_app_revision_id_by_name(app_name)) end |
#delete_flow_by_id(app_revision_id, flow_id) ⇒ Object
Delete a specific flow
56 57 58 59 60 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 56 def delete_flow_by_id(app_revision_id, flow_id) response = rest_delete("/BusinessFlow/rest/v1/applications/#{app_revision_id}/flows/#{flow_id}") response_handler(response) true end |
#get_app_revision_id_by_name(app_name) ⇒ Boolean
Get latest application revision id by application name
145 146 147 148 149 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 145 def get_app_revision_id_by_name(app_name) response = rest_get("/BusinessFlow/rest/v1/applications/name/#{app_name}") app = response_handler(response) app['revisionID'] end |
#get_application_flow_by_name(app_revision_id, flow_name) ⇒ Object
Fetch an application flow by it’s name
127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 127 def get_application_flow_by_name(app_revision_id, flow_name) flows = get_application_flows(app_revision_id) requested_flow = flows.find do |flow| break flow if flow['name'] == flow_name end if requested_flow.nil? raise( "Unable to find flow by name. Application revision id: #{app_revision_id}, flow_name: #{flow_name}." ) end requested_flow end |
#get_application_flows(app_revision_id) ⇒ Array<Hash>
Get list of application flows for an application revision id
37 38 39 40 41 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 37 def get_application_flows(app_revision_id) response = rest_get("/BusinessFlow/rest/v1/applications/#{app_revision_id}/flows") flows = response_handler(response) flows.map { |flow| flow['flowType'] == 'APPLICATION_FLOW' ? flow : nil }.compact end |
#get_application_flows_hash(app_revision_id) ⇒ Hash
Get application flows from the server as a hash from flow name it it’s content
47 48 49 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 47 def get_application_flows_hash(app_revision_id) Hash[get_application_flows(app_revision_id).map { |flow| [flow['name'], flow] }] end |
#get_flow_connectivity(app_revision_id, flow_id) ⇒ String
Get connectivity status for a flow
67 68 69 70 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 67 def get_flow_connectivity(app_revision_id, flow_id) response = rest_post("/BusinessFlow/rest/v1/applications/#{app_revision_id}/flows/#{flow_id}/check_connectivity") response_handler(response) end |
#implement_app_flows_plan(app_name, new_app_flows, flows_from_server, flows_to_delete, flows_to_create, flows_to_modify) ⇒ Object
Create/modify/delete application2 flows to match a given flow plan returned by ‘plan_application_flows’ param [Array<String>] flows_to_modify List of network flow names to delete and re-create with the new definition
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 228 def implement_app_flows_plan( app_name, new_app_flows, flows_from_server, flows_to_delete, flows_to_create, flows_to_modify ) # Get the app revision id app_revision_id = get_app_revision_id_by_name(app_name) # This param is used to determine if it is necessary to update the app_revision_id is_draft_revision = false # Delete all the flows for deletion and modification (flows_to_delete | flows_to_modify).each do |flow_name_to_delete| delete_flow_by_id(app_revision_id, flows_from_server[flow_name_to_delete]['flowID']) next if is_draft_revision app_revision_id = get_app_revision_id_by_name(app_name) # Refetch the fresh flows from the server, as a new application revision has been created # and it's flow IDs have been change. Only that way we can make sure that the following flow deletions # by name will work as expected flows_from_server = get_application_flows(app_revision_id) is_draft_revision = true end # Create all the new + modified flows (flows_to_create | flows_to_modify).each do |flow_name_to_create| new_flow_data = new_app_flows[flow_name_to_create] create_application_flow( app_revision_id, flow_name_to_create, # Document those key fields somewhere so users know how what is the format of app_flows object # that is provided to this function new_flow_data['sources'], new_flow_data['destinations'], new_flow_data['services'], new_flow_data.fetch('users', []), new_flow_data.fetch('applications', []), new_flow_data.fetch('comment', '') ) unless is_draft_revision app_revision_id = get_app_revision_id_by_name(app_name) is_draft_revision = true end end apply_application_draft(app_revision_id) if is_draft_revision end |
#login ⇒ Array<Hash>
Request login to get session cookie credentials
29 30 31 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 29 def login response_handler(rest_post('/BusinessFlow/rest/v1/login')) end |
#plan_application_flows(server_app_flows, new_app_flows) ⇒ Object
Return a plan for modifying application flows based on current and newly proposed application flows definition
204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 204 def plan_application_flows(server_app_flows, new_app_flows) current_flow_names = Set.new(server_app_flows.keys) new_flow_names = Set.new(new_app_flows.keys) # Calculate the flows_to_delete, flows_to_create and flows_to_modify and unchanging_flows flows_to_delete = current_flow_names - new_flow_names flows_to_create = new_flow_names - current_flow_names flows_to_modify = Set.new((new_flow_names & current_flow_names).map do |flow_name| flow_on_server = server_app_flows[flow_name] new_flow_definition = new_app_flows[flow_name] ALGOSEC_SDK::AreFlowsEqual.flows_equal?(new_flow_definition, flow_on_server) ? nil : flow_name end.compact) [flows_to_delete, flows_to_create, flows_to_modify] end |
#search_network_object(ip_or_subnet, search_type) ⇒ Object
Search a network object
191 192 193 194 195 196 197 |
# File 'lib/algosec-sdk/helpers/business_flow_helper.rb', line 191 def search_network_object(ip_or_subnet, search_type) response = rest_get( '/BusinessFlow/rest/v1/network_objects/find', query: { address: ip_or_subnet, type: search_type } ) response_handler(response) end |