Project

General

Profile

Revision f02a9ce2

Added by Sebastian Gräßl over 5 years ago

Fixes #18733 - Prevent fallback to Docker Hub on registry search

When searching for an external registry the search would show
results from Docker Hub due to it searching via the compute
resource.

By using a registry parameter to indicate which search tab is
active this gets prevented on the backend as well as on the
client by not searching when no registry is selected.

View differences:

app/controllers/image_search_controller.rb
1 1
class ImageSearchController < ::ApplicationController
2
  before_filter :find_resource
3

  
4
  # this is incredibly odd. for some reason, rails sees the
5
  # requests ImageSearchControllerTest makes as requests from another host
6
  # thus, violating CSRF.
7
  protect_from_forgery :only => :nothing if Rails.env.test?
8

  
9 2
  def auto_complete_repository_name
10 3
    catch_network_errors do
11
      text = if use_hub?
12
               hub_image_exists?(params[:search])
13
             else
14
               registry_image_exists?(params[:search])
15
             end
16
      render :text => text.to_s
4
      available = image_search_service.available?(params[:search])
5
      render :text => available.to_s
17 6
    end
18 7
  end
19 8

  
20 9
  def auto_complete_image_tag
21 10
    catch_network_errors do
22
      # This is the format jQuery UI autocomplete expects
23
      tags = if use_hub?
24
               hub_auto_complete_image_tags(params[:search])
25
             else
26
               registry_auto_complete_image_tags(params[:search])
27
             end
28

  
29
      tags = tags.map do |tag|
30
        tag = CGI.escapeHTML(tag)
31
        { :label => tag, :value => tag }
32
      end
11
      tags = image_search_service.search({
12
        term: params[:search],
13
        tags: 'true'
14
      })
33 15

  
34 16
      respond_to do |format|
35 17
        format.js do
36
          render :json => tags
18
          render :json => prepare_for_autocomplete(tags)
37 19
        end
38 20
      end
39 21
    end
......
41 23

  
42 24
  def search_repository
43 25
    catch_network_errors do
44
      repositories = if use_hub?
45
                       hub_search_image(params[:search])
46
                     else
47
                       registry_search_image(params[:search])
48
                     end
26
      repositories = image_search_service.search({
27
        term: params[:search].split(':').first,
28
        tags: 'false'
29
      })
49 30

  
50 31
      respond_to do |format|
51 32
        format.js do
......
57 38
    end
58 39
  end
59 40

  
41
  private
42

  
60 43
  def catch_network_errors
61 44
    yield
62 45
  rescue Docker::Error::NotFoundError => e
......
72 55
    @registry.nil?
73 56
  end
74 57

  
75
  def hub_image_exists?(terms)
76
    @compute_resource.exist?(terms)
77
  end
78

  
79
  def hub_auto_complete_image_tags(terms)
80
    @compute_resource.tags(terms)
81
  end
82

  
83
  def hub_search_image(terms)
84
    @compute_resource.search(terms).map do |item|
85
      # el7 returns -> "name" => "docker.io: docker.io/centos",
86
      # while f20 returns -> "name" => "centos"
87
      # we need repo name to be => "docker.io/centos" for el7 and "centos" for fedora
88
      # to ensure proper search with respect to the tags, image creation etc.
89
      new_item = item.clone
90
      new_item["name"] = item["name"].split.last
91
      new_item
92
    end
93
  end
94

  
95
  def registry_image_exists?(term)
96
    result = ::Service::RegistryApi.new(:url => @registry.url,
97
                                        :user => @registry.username,
98
                                        :password => @registry.password).search(term)
99
    registry_name = if term.split('/').size > 1
100
                      term
101
                    else
102
                      "library/#{term}"
103
                    end
104

  
105
    result['results'].any? { |r| r['name'] == registry_name }
106
  end
107

  
108
  def registry_auto_complete_image_tags(terms)
109
    ::Service::RegistryApi.new(:url => @registry.url,
110
                               :user => @registry.username,
111
                               :password => @registry.password).tags(terms).map { |t| t['name'] }
112
  end
113

  
114
  def registry_search_image(terms)
115
    r = ::Service::RegistryApi.new(:url => @registry.url,
116
                                   :user => @registry.username,
117
                                   :password => @registry.password).search(terms)
118
    r['results']
119
  end
120

  
121 58
  def action_permission
122 59
    case params[:action]
123 60
    when 'auto_complete_repository_name', 'auto_complete_image_tag', 'search_repository'
......
127 64
    end
128 65
  end
129 66

  
130
  def find_resource
131
    if params[:registry_id].present?
132
      @registry = DockerRegistry.authorized(:view_registries).find(params[:registry_id])
133
    else
134
      @compute_resource = ComputeResource.authorized(:view_compute_resources).find(params[:id])
67
  # This is the format jQuery UI autocomplete expects
68
  def prepare_for_autocomplete(tags)
69
    tags.map do |tag|
70
      tag = tag.is_a?(Hash) ? tag.fetch('name', tag) : tag
71
      tag = CGI.escapeHTML(tag)
72
      { :label => tag, :value => tag }
73
    end
74
  end
75

  
76
  def image_search_service
77
    @image_search_service ||= ForemanDocker::ImageSearch.new(*sources)
78
  end
79

  
80
  def sources
81
    if params[:registry] == 'hub'
82
      @registry ||= Service::RegistryApi.docker_hub
83
      @compute_resource ||= ComputeResource.authorized(:view_compute_resources).find(params[:id])
84
      [@registry, @compute_resource]
85
    elsif params[:registry] == 'registry' && params[:registry_id].present?
86
      @registry ||= DockerRegistry.authorized(:view_registries)
87
        .find(params[:registry_id]).api
88
      [@registry]
135 89
    end
136
  rescue ActiveRecord::RecordNotFound
137
    not_found
138 90
  end
139 91
end

Also available in: Unified diff