Skip to content

Commit

Permalink
[webui][api] interface to access a project's public key and ssl certi…
Browse files Browse the repository at this point in the history
…ficate

rename PublicKeyInfoController to PublicKey & use models for handling the backend response

use find_by! instead of having unecssary extra line

revert the find_by! commit

WIP: add webui project publickey controller

change class to module

change to multi-line class namespace syntax

remove webui public key controller

model: Project::PublicKey => PublicKey

Revert "remove webui public key controller"

This reverts commit 53d2f3e.

webui projects controller lets you download the public key

enable eager_load in development

make the public key controller publicly accessible

controller spec which uses stub_request

add 404 response and link to download public key

add webui controller spec

use faker to generate the "gpg key" for rspec tests

memoize project.public_key

return the ssl cert as well in the xml response

add ssl certificate controller

move the source api url from the specs to the model so its only defined in one place
  • Loading branch information
evanrolfe committed Jan 9, 2017
1 parent 919f034 commit 6383479
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 13 deletions.
11 changes: 11 additions & 0 deletions src/api/app/controllers/application_controller.rb
Expand Up @@ -569,6 +569,17 @@ def set_response_format_to_xml
request.format = :xml if request.format == :html
end

def extract_user_public
# to become _public_ special user
if ::Configuration.anonymous
load_nobody
return true
end
logger.error 'No public access is configured'
render_error( message: 'No public access is configured', status: 401 )
false
end

private

def forward_from_backend(path)
Expand Down
17 changes: 17 additions & 0 deletions src/api/app/controllers/project/public_key_controller.rb
@@ -0,0 +1,17 @@
class Project
class PublicKeyController < ApplicationController
before_action :extract_user_public
skip_before_action :extract_user
skip_before_action :require_login

def show
project = Project.find_by_name!(params[:project_name])

if project.public_key.present?
render :show, locals: { public_key: project.public_key }
else
render nothing: true, status: :not_found
end
end
end
end
11 changes: 0 additions & 11 deletions src/api/app/controllers/public_controller.rb
Expand Up @@ -193,17 +193,6 @@ def unshift_public(path)
end
end

def extract_user_public
# to become _public_ special user
if ::Configuration.anonymous
load_nobody
return true
end
logger.error 'No public access is configured'
render_error( message: 'No public access is configured', status: 401 )
false
end

def check_package_access(project, package, use_source = true)
# don't use the cache for use_source
if use_source
Expand Down
19 changes: 19 additions & 0 deletions src/api/app/controllers/webui/project/public_key_controller.rb
@@ -0,0 +1,19 @@
module Webui
module Project
class PublicKeyController < WebuiController
def show
project = ::Project.find_by_name!(params[:project_name])

if project.public_key.present?
send_data(
project.public_key.content,
disposition: 'attachment',
filename: "#{project.title}_key.pub"
)
else
render nothing: true, status: :not_found
end
end
end
end
end
@@ -0,0 +1,19 @@
module Webui
module Project
class SslCertificateController < WebuiController
def show
project = ::Project.find_by_name!(params[:project_name])

if project.public_key.present? && project.public_key.ssl_certificate.present?
send_data(
project.public_key.ssl_certificate,
disposition: 'attachment',
filename: "#{project.title}_ssl.cert"
)
else
render nothing: true, status: :not_found
end
end
end
end
end
4 changes: 4 additions & 0 deletions src/api/app/models/project.rb
Expand Up @@ -1857,6 +1857,10 @@ def image_template?
where(attrib_types: { name: 'ImageTemplates' }, attrib_namespaces: { name: 'OBS' }).exists?
end

def public_key
@public_key ||= PublicKey.find_by_project_name(name)
end

private

def discard_cache
Expand Down
29 changes: 29 additions & 0 deletions src/api/app/models/public_key.rb
@@ -0,0 +1,29 @@
class PublicKey
include ActiveModel::Model

attr_accessor :content, :algorithm, :ssl_certificate

def self.find_by_project_name(project_name)
response = Suse::Backend.get(backend_url(project_name)).body
parsed_response = Xmlhash.parse(response)

if parsed_response['pubkey'].present?
public_key_params = {
content: parsed_response['pubkey']['_content'],
algorithm: parsed_response['pubkey']['algo']
}

if parsed_response['sslcert'].present?
public_key_params[:ssl_certificate] = parsed_response['sslcert']
end

new(public_key_params)
end
end

private

def self.backend_url(project_name)
"/source/#{project_name}/_keyinfo?withsslcert=1"
end
end
4 changes: 4 additions & 0 deletions src/api/app/views/project/public_key/show.xml.builder
@@ -0,0 +1,4 @@
xml.public_key algorithm: public_key.algorithm do
xml.content public_key.content
xml.ssl_certificate public_key.ssl_certificate
end
10 changes: 10 additions & 0 deletions src/api/app/views/webui/project/show.html.erb
Expand Up @@ -141,6 +141,16 @@
<%= link_to(sprited_text('brick_go', 'Submit as update'), { controller: 'project', action: 'incident_request_dialog', project: @project }, remote: true) %>
</li>
<% end %>
<% if @project.public_key.present? %>
<li>
<%= link_to(sprited_text('key', 'Download GPG Key'), project_public_key_path(project_name: @project.name)) %>
</li>
<% end %>
<% if @project.public_key.present? && @project.public_key.ssl_certificate.present? %>
<li>
<%= link_to(sprited_text('key', 'Download SSL Certificate'), project_ssl_certificate_path(project_name: @project.name)) %>
</li>
<% end %>
<% end %>
<% end %>
<li>
Expand Down
4 changes: 2 additions & 2 deletions src/api/config/environments/development.rb
Expand Up @@ -8,8 +8,8 @@
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false

# Do not eager load code on boot.
config.eager_load = false
# Eager load code on boot.
config.eager_load = true

# Show full error reports and disable caching
config.consider_all_requests_local = true
Expand Down
9 changes: 9 additions & 0 deletions src/api/config/routes.rb
Expand Up @@ -254,6 +254,11 @@ def self.public_or_about_path?(request)
post 'project/comments/:project' => :save_comment, constraints: cons, as: 'save_project_comment'
end

resources :project, only: [], param: :name do
resource :public_key, controller: 'webui/project/public_key', only: [:show]
resource :ssl_certificate, controller: 'webui/project/ssl_certificate', only: [:show]
end

controller 'webui/request' do
get 'request/add_reviewer_dialog' => :add_reviewer_dialog
post 'request/add_reviewer' => :add_reviewer
Expand Down Expand Up @@ -698,6 +703,10 @@ def self.public_or_about_path?(request)
get 'main/sitemap' => 'webui/main#sitemap'
get 'main/sitemap_projects' => 'webui/main#sitemap_projects'
get 'main/sitemap_packages/:listaction' => 'webui/main#sitemap_packages'

resources :project, only: [], param: :name do
resource :public_key, controller: 'project/public_key', only: [:show]
end
end

OBSEngine::Base.subclasses.each do |engine|
Expand Down
@@ -0,0 +1,49 @@
require 'rails_helper'
require 'webmock/rspec'

RSpec.describe Project::PublicKeyController, type: :controller, vcr: true do
describe 'GET #show' do
let(:project) do
create(
:project,
name: "test_project",
title: "Test Project"
)
end

let(:backend_url) { CONFIG['source_url'] + PublicKey.send(:backend_url, project.name) }

before do
stub_request(:get, backend_url).and_return(body: keyinfo_response)

get :show, params: { format: :xml, project_name: project.name }
end

context 'with a project that has a public key and an ssl certificate' do
let(:gpg_public_key) { Faker::Lorem.characters(1024) }
let(:ssl_certificate) { Faker::Lorem.characters(1024) }
let(:keyinfo_response) do
%Q{<keyinfo project="Test"><pubkey algo="rsa">#{gpg_public_key}</pubkey><sslcert>#{ssl_certificate}</sslcert></keyinfo>}
end

it { is_expected.to respond_with(:success) }
it { is_expected.to render_template(:show) }
end

context 'with a project that has a public key and no ssl certificate' do
let(:gpg_public_key) { Faker::Lorem.characters(1024) }
let(:keyinfo_response) do
%Q{<keyinfo project="Test"><pubkey algo="rsa">#{gpg_public_key}</pubkey></keyinfo>}
end

it { is_expected.to respond_with(:success) }
it { is_expected.to render_template(:show) }
end

context 'with a project that has no public key' do
let(:keyinfo_response) { '<keyinfo />' }

it { expect(response.status).to eq(404) }
end
end
end
@@ -0,0 +1,38 @@
require 'rails_helper'
require 'webmock/rspec'

RSpec.describe Webui::Project::PublicKeyController, type: :controller, vcr: true do
describe 'GET #show' do
let(:project) do
create(
:project,
name: "test_project",
title: "Test Project"
)
end

let(:backend_url) { CONFIG['source_url'] + PublicKey.send(:backend_url, project.name) }

before do
stub_request(:get, backend_url).and_return(body: keyinfo_response)

get :show, params: { project_name: project.name }
end

context 'with a project that has a public key' do
let(:gpg_public_key) { Faker::Lorem.characters(1024) }
let(:keyinfo_response) do
%Q{<keyinfo project="Test"><pubkey algo="rsa">#{gpg_public_key}</pubkey></keyinfo>}
end

it { expect(response.header['Content-Disposition']).to include('attachment') }
it { expect(response.body.strip).to eq(gpg_public_key) }
end

context 'with a project that has no public key' do
let(:keyinfo_response) { '<keyinfo />' }

it { expect(response.status).to eq(404) }
end
end
end
@@ -0,0 +1,42 @@
require 'rails_helper'
require 'webmock/rspec'

RSpec.describe Webui::Project::SslCertificateController, type: :controller, vcr: true do
describe 'GET #show' do
let(:project) do
create(
:project,
name: "test_project",
title: "Test Project"
)
end

let(:backend_url) { CONFIG['source_url'] + PublicKey.send(:backend_url, project.name) }

before do
stub_request(:get, backend_url).and_return(body: keyinfo_response)

get :show, params: { project_name: project.name }
end

context 'with a project that has an ssl certificate' do
let(:gpg_public_key) { Faker::Lorem.characters(1024) }
let(:ssl_certificate) { Faker::Lorem.characters(1024) }
let(:keyinfo_response) do
%Q{<keyinfo project="Test"><pubkey algo="rsa">#{gpg_public_key}</pubkey><sslcert>#{ssl_certificate}</sslcert></keyinfo>}
end

it { expect(response.header['Content-Disposition']).to include('attachment') }
it { expect(response.body.strip).to eq(ssl_certificate) }
end

context 'with a project that has no ssl certificate' do
let(:gpg_public_key) { Faker::Lorem.characters(1024) }
let(:keyinfo_response) do
%Q{<keyinfo project="Test"><pubkey algo="rsa">#{gpg_public_key}</pubkey></keyinfo>}
end

it { expect(response.status).to eq(404) }
end
end
end

0 comments on commit 6383479

Please sign in to comment.