Commit 81258588 authored by Yorick Peterse's avatar Yorick Peterse

Merge branch 'find-key-by-fingerprint' into 'master'

Add find key by base64 key or fingerprint to the internal API

See merge request !250
parents 78d9df93 190a991a
class AddFingerprintIndex < ActiveRecord::Migration
disable_ddl_transaction!
def change
args = [:keys, :fingerprint]
if Gitlab::Database.postgresql?
args << { algorithm: :concurrently }
end
add_index(*args)
end
end
......@@ -520,6 +520,7 @@ ActiveRecord::Schema.define(version: 20160320204112) do
end
add_index "keys", ["created_at", "id"], name: "index_keys_on_created_at_and_id", using: :btree
add_index "keys", ["fingerprint"], name: "index_keys_on_fingerprint", using: :btree
add_index "keys", ["user_id"], name: "index_keys_on_user_id", using: :btree
create_table "label_links", force: :cascade do |t|
......
......@@ -25,7 +25,7 @@ module API
post "/allowed" do
status 200
actor =
actor =
if params[:key_id]
Key.find_by(id: params[:key_id])
elsif params[:user_id]
......@@ -33,7 +33,7 @@ module API
end
project_path = params[:project]
# Check for *.wiki repositories.
# Strip out the .wiki from the pathname before finding the
# project. This applies the correct project permissions to
......@@ -52,6 +52,18 @@ module API
access.check(params[:action], params[:changes])
end
#
# Get a ssh key using the fingerprint
#
get "/authorized_keys" do
fingerprint = params.fetch(:fingerprint) do
Gitlab::InsecureKeyFingerprint.new(params.fetch(:key)).fingerprint
end
key = Key.find_by(fingerprint: fingerprint)
not_found!("Key") if key.nil?
present key, with: Entities::SSHKey
end
#
# Discover user by ssh key
#
......
module Gitlab
#
# Calculates the fingerprint of a given key without using
# openssh key validations. For this reason, only use
# for calculating the fingerprint to find the key with it.
#
# DO NOT use it for checking the validity of a ssh key.
#
class InsecureKeyFingerprint
attr_accessor :key
#
# Gets the base64 encoded string representing a rsa or dsa key
#
def initialize(key_base64)
@key = key_base64
end
def fingerprint
OpenSSL::Digest::MD5.hexdigest(Base64.decode64(@key)).scan(/../).join(':')
end
end
end
......@@ -49,7 +49,7 @@ module Gitlab
required_version_info = Gitlab::VersionInfo.new(6, 8)
version_info >= required_version_info
version_info >= required_version_info
end
end
end
require "spec_helper"
describe Gitlab::KeyFingerprint, lib: true do
describe "SSH Keys" do
let(:key) { "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" }
let(:fingerprint) { "3f:a2:ee:de:b5:de:53:c3:aa:2f:9c:45:24:4c:47:7b" }
describe "#fingerprint" do
it "generates the key's fingerprint" do
expect(Gitlab::KeyFingerprint.new(key).fingerprint).to eq(fingerprint)
describe Gitlab::KeyFingerprint, lib: true do
describe "#fingerprint" do
it "generates the key's fingerprint" do
expect(Gitlab::KeyFingerprint.new(key).fingerprint).to eq(fingerprint)
end
end
end
describe Gitlab::InsecureKeyFingerprint, lib: true do
describe "#fingerprint" do
it "generates the key's fingerprint" do
expect(Gitlab::InsecureKeyFingerprint.new(key.split[1]).fingerprint).to eq(fingerprint)
end
end
end
end
......@@ -48,6 +48,54 @@ describe API::API, api: true do
end
end
describe "GET /internal/authorized_keys" do
context "unsing an existing key's fingerprint" do
it "finds the key" do
get(api('/internal/authorized_keys'), fingerprint: key.fingerprint, secret_token: secret_token)
expect(response.status).to eq(200)
expect(json_response["key"]).to eq(key.key)
end
end
context "non existing key's fingerprint" do
it "returns 404" do
get(api('/internal/authorized_keys'), fingerprint: "no:t-:va:li:d0", secret_token: secret_token)
expect(response.status).to eq(404)
end
end
context "using a partial fingerprint" do
it "returns 404" do
get(api('/internal/authorized_keys'), fingerprint: "#{key.fingerprint[0..5]}%", secret_token: secret_token)
expect(response.status).to eq(404)
end
end
context "sending the key" do
it "finds the key" do
get(api('/internal/authorized_keys'), key: key.key.split[1], secret_token: secret_token)
expect(response.status).to eq(200)
expect(json_response["key"]).to eq(key.key)
end
it "returns 404 with a partial key" do
get(api('/internal/authorized_keys'), key: key.key.split[1][0...-3], secret_token: secret_token)
expect(response.status).to eq(404)
end
it "returns 404 with an not valid base64 string" do
get(api('/internal/authorized_keys'), key: "whatever!", secret_token: secret_token)
expect(response.status).to eq(404)
end
end
end
describe "POST /internal/allowed" do
context "access granted" do
before do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment