Class: Puppet::Network::HTTP::API::IndirectedRoutes

Inherits:
Object
  • Object
show all
Includes:
Authorization
Defined in:
lib/puppet/network/http/api/indirected_routes.rb

Constant Summary collapse

METHOD_MAP =

How we map http methods and the indirection name in the URI to an indirection method.

{
  "GET" => {
    :plural => :search,
    :singular => :find
  },
  "POST" => {
    :singular => :find,
  },
  "PUT" => {
    :singular => :save
  },
  "DELETE" => {
    :singular => :destroy
  },
  "HEAD" => {
    :singular => :head
  }
}
IndirectionType =
Puppet::Network::HTTP::API::IndirectionType

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Authorization

#authconfig, authconfigloader_class=, #check_authorization

Class Method Details

.request_to_uri(request) ⇒ Object


123
124
125
126
# File 'lib/puppet/network/http/api/indirected_routes.rb', line 123

def self.request_to_uri(request)
  uri, body = request_to_uri_and_body(request)
  "#{uri}?#{body}"
end

.request_to_uri_and_body(request) ⇒ Object


128
129
130
131
132
# File 'lib/puppet/network/http/api/indirected_routes.rb', line 128

def self.request_to_uri_and_body(request)
  url_prefix = IndirectionType.url_prefix_for(request.indirection_name.to_s)
  indirection = request.method == :search ? pluralize(request.indirection_name.to_s) : request.indirection_name.to_s
  ["#{url_prefix}/#{indirection}/#{Puppet::Util.uri_encode(request.key)}", "environment=#{request.environment.name}&#{request.query_string}"]
end

.routesObject


30
31
32
# File 'lib/puppet/network/http/api/indirected_routes.rb', line 30

def self.routes
  Puppet::Network::HTTP::Route.path(/.*/).any(new)
end

Instance Method Details

#call(request, response) ⇒ Object

handle an HTTP request


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/puppet/network/http/api/indirected_routes.rb', line 35

def call(request, response)
  indirection, method, key, params = uri2indirection(request.method, request.path, request.params)
  certificate = request.client_cert

  if !indirection.allow_remote_requests?
    # TODO: should we tell the user we found an indirection but it doesn't
    # allow remote requests, or just pretend there's no handler at all? what
    # are the security implications for the former?
    raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new(_("No handler for %{indirection}") % { indirection: indirection.name }, :NO_INDIRECTION_REMOTE_REQUESTS)
  end

  overrides = {
    trusted_information: Puppet::Context::TrustedInformation.remote(params[:authenticated], params[:node], certificate),
  }
  if params[:environment]
    overrides[:current_environment] = params[:environment]
  end

  Puppet.override(overrides) do
    send("do_#{method}", indirection, key, params, request, response)
  end
end

#uri2indirection(http_method, uri, params) ⇒ Object


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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
121
# File 'lib/puppet/network/http/api/indirected_routes.rb', line 58

def uri2indirection(http_method, uri, params)
  # the first field is always nil because of the leading slash,
  indirection_type, version, indirection_name, key = uri.split("/", 5)[1..-1]
  url_prefix = "/#{indirection_type}/#{version}"
  environment = params.delete(:environment)

  if indirection_name !~ /^\w+$/
    raise Puppet::Network::HTTP::Error::HTTPBadRequestError.new(
      _("The indirection name must be purely alphanumeric, not '%{indirection_name}'") % { indirection_name: indirection_name })
  end

  # this also depluralizes the indirection_name if it is a search
  method = indirection_method(http_method, indirection_name)

  # check whether this indirection matches the prefix and version in the
  # request
  if url_prefix != IndirectionType.url_prefix_for(indirection_name)
    raise Puppet::Network::HTTP::Error::HTTPBadRequestError.new(
      _("Indirection '%{indirection_name}' does not match url prefix '%{url_prefix}'") % { indirection_name: indirection_name, url_prefix: url_prefix })
  end

  indirection = Puppet::Indirector::Indirection.instance(indirection_name.to_sym)
  if !indirection
    raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new(
      _("Could not find indirection '%{indirection_name}'") % { indirection_name: indirection_name },
      Puppet::Network::HTTP::Issues::HANDLER_NOT_FOUND)
  end

  if !environment
    raise Puppet::Network::HTTP::Error::HTTPBadRequestError.new(
      _("An environment parameter must be specified"))
  end

  if ! Puppet::Node::Environment.valid_name?(environment)
    raise Puppet::Network::HTTP::Error::HTTPBadRequestError.new(
      _("The environment must be purely alphanumeric, not '%{environment}'") % { environment: environment })
  end

  configured_environment = Puppet.lookup(:environments).get(environment)
  unless configured_environment.nil?
    configured_environment = configured_environment.override_from_commandline(Puppet.settings)
    params[:environment] = configured_environment
  end

  begin
    check_authorization(method, "#{url_prefix}/#{indirection_name}/#{key}", params)
  rescue Puppet::Network::AuthorizationError => e
    raise Puppet::Network::HTTP::Error::HTTPNotAuthorizedError.new(e.message)
  end

  if configured_environment.nil?
    raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new(
      _("Could not find environment '%{environment}'") % { environment: environment })
  end

  params.delete(:bucket_path)

  if key == "" or key.nil?
    raise Puppet::Network::HTTP::Error::HTTPBadRequestError.new(
      _("No request key specified in %{uri}") % { uri: uri })
  end

  [indirection, method, key, params]
end