class ThreeScaleToolbox::OpenAPI::OAS3

OAS3 object

Constants

META_SCHEMA_PATH

Attributes

definition[R]

Public Class Methods

build(path, raw, validate: true) click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 37
def self.build(path, raw, validate: true)
  self.validate(raw) if validate

  new(path, raw)
end
new(path, raw) click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 117
def initialize(path, raw)
  parser = OasParser::Parser.new(path, raw).resolve
  @definition = OasParser::Definition.new(parser, path)
end
validate(raw) click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 32
def self.validate(raw)
  meta_schema = JSON.parse(File.read(META_SCHEMA_PATH))
  JSON::Validator.validate!(meta_schema, raw)
end

Public Instance Methods

base_path() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 57
def base_path
  # If there are many? take first
  # From https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#openapi-object
  # If the servers property is not provided, or is an empty array,
  # the default value would be a Server Object with a url value of /
  server_objects(&:path).first || '/'
end
description() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 49
def description
  definition.info['description']
end
host() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 65
def host
  # If there are many? take first
  server_objects { |url| "#{url.host}:#{url.port}" }.first
end
operations() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 75
def operations
  @operations ||= parse_operations
end
scheme() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 70
def scheme
  # If there are many? take first
  server_objects(&:scheme).first
end
security() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 79
def security
  @security ||= parse_security
end
service_backend_version() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 83
def service_backend_version
  # default authentication mode if no security requirement
  return '1' if security.nil?

  case security[:type]
  when 'oauth2'
    'oidc'
  when 'apiKey'
    '1'
  else
    raise ThreeScaleToolbox::Error, "Unexpected security scheme type #{security[:type]}"
  end
end
set_oauth2_urls(spec, sec_scheme_id, authorization_url, token_url) click to toggle source

Update given spec with urls It is expected identified security scheme to be oauth2 type

# File lib/3scale_toolbox/openapi/oas3.rb, line 100
def set_oauth2_urls(spec, sec_scheme_id, authorization_url, token_url)
  sec_scheme_obj = spec.dig('components', 'securitySchemes', sec_scheme_id)
  if sec_scheme_obj.nil? || sec_scheme_obj['type'] != 'oauth2'
    raise ThreeScaleToolbox::Error, "Expected security scheme {#{sec_scheme_id}} not found or not oauth2"
  end

  flow_key, flow_obj = sec_scheme_obj['flows'].first
  flow_obj['authorizationUrl'] = authorization_url if %w[implicit authorizationCode].include?(flow_key)
  flow_obj['tokenUrl'] = token_url if %w[password clientCredentials authorizationCode].include?(flow_key)
end
set_server_url(spec, url) click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 111
def set_server_url(spec, url)
  spec['servers'] = [{ 'url' => url }]
end
title() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 45
def title
  definition.info['title']
end
version() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 53
def version
  definition.info['version']
end

Private Instance Methods

convert_flow(flow_name) click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 216
def convert_flow(flow_name)
  case flow_name
  when 'implicit'
    :implicit_flow_enabled
  when 'password'
    :direct_access_grants_enabled
  when 'clientCredentials'
    :service_accounts_enabled
  when 'authorizationCode'
    :standard_flow_enabled
  else
    raise ThreeScaleToolbox::Error, "Unexpected security flow field #{flow_name}"
  end
end
erbfying_template(template) click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 142
def erbfying_template(template)
  # A URL is composed from a limited set of characters belonging to the US-ASCII character set.
  # These characters include digits (0-9), letters(A-Z, a-z), and a few special characters ("-", ".", "_", "~").
  # https://www.urlencoder.io/learn/
  tmp = template.gsub '{', '<%='
  tmp.gsub '}', '%>'
end
fetch_security_scheme(name) click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 194
def fetch_security_scheme(name)
  security_schemes.fetch(name) do |el|
    raise ThreeScaleToolbox::Error, "OAS3 parsing error: #{el} not found in security schemes"
  end
end
global_security_requirements() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 174
def global_security_requirements
  @global_security_requirements ||= parse_global_security_reqs
end
parse_flows(flows_object) click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 208
def parse_flows(flows_object)
  return nil if flows_object.nil?

  raise ThreeScaleToolbox::Error, 'Invalid OAS: multiple flows' if flows_object.size > 1

  convert_flow(flows_object.keys.first)
end
parse_global_security_reqs() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 178
def parse_global_security_reqs
  security_requirements.flat_map do |sec_req|
    sec_req.map do |sec_item_name, sec_item|
      sec_def = fetch_security_scheme(sec_item_name)
      {
        id: sec_item_name,
        type: sec_def['type'],
        name: sec_def['name'],
        in_f: sec_def['in'],
        flow: parse_flows(sec_def['flows']),
        scopes: sec_item
      }
    end
  end
end
parse_operations() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 154
def parse_operations
  definition.paths.flat_map do |path_obj|
    path_obj.endpoints.flat_map do |endpoint|
      {
        verb: endpoint.method,
        path: endpoint.path.path,
        description: endpoint.description,
        operation_id: endpoint.operationId
      }
    end
  end
end
parse_security() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 167
def parse_security
  raise ThreeScaleToolbox::Error, 'Invalid OAS: multiple security requirements' \
    if global_security_requirements.size > 1

  global_security_requirements.first
end
rendered_url(server_object) click to toggle source

OAS3 server object variable substitution

# File lib/3scale_toolbox/openapi/oas3.rb, line 129
def rendered_url(server_object)
  template = erbfying_template(server_object.fetch('url'))
  vars = server_object_variables(server_object['variables'])
  ERB.new(template).result(OpenStruct.new(vars).instance_eval { binding })
end
security_requirements() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 200
def security_requirements
  definition.security || []
end
security_schemes() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 204
def security_schemes
  (definition.components || {})['securitySchemes'] || {}
end
server_object_variables(variables) click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 135
def server_object_variables(variables)
  vars = (variables || {}).each_with_object({}) do |(key, value), a|
    a[key] = value['default']
  end
  JSON.parse(vars.to_json, symbolize_names: true)
end
server_objects() { |parse_uri rendered_url(s)| ... } click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 122
def server_objects
  servers.map do |s|
    yield Helper.parse_uri rendered_url(s)
  end
end
servers() click to toggle source
# File lib/3scale_toolbox/openapi/oas3.rb, line 150
def servers
  definition.servers || []
end