Refactor key loading to support PEM + fix issue #62
This commit is contained in:
parent
01fc90b3fc
commit
1c849c7e7a
|
@ -0,0 +1,93 @@
|
||||||
|
# Copyright 2010 Google Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
module Google
|
||||||
|
class APIClient
|
||||||
|
##
|
||||||
|
# Helper for loading keys from the PKCS12 files downloaded when
|
||||||
|
# setting up service accounts at the APIs Console.
|
||||||
|
#
|
||||||
|
module KeyUtils
|
||||||
|
##
|
||||||
|
# Loads a key from PKCS12 file, assuming a single private key
|
||||||
|
# is present.
|
||||||
|
#
|
||||||
|
# @param [String] keyfile
|
||||||
|
# Path of the PKCS12 file to load. If not a path to an actual file,
|
||||||
|
# assumes the string is the content of the file itself.
|
||||||
|
# @param [String] passphrase
|
||||||
|
# Passphrase for unlocking the private key
|
||||||
|
#
|
||||||
|
# @return [OpenSSL::PKey] The private key for signing assertions.
|
||||||
|
def self.load_from_pkcs12(keyfile, passphrase)
|
||||||
|
load_key(keyfile, passphrase) do |content, passphrase|
|
||||||
|
OpenSSL::PKCS12.new(content, passphrase).key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Loads a key from a PEM file.
|
||||||
|
#
|
||||||
|
# @param [String] keyfile
|
||||||
|
# Path of the PEM file to load. If not a path to an actual file,
|
||||||
|
# assumes the string is the content of the file itself.
|
||||||
|
# @param [String] passphrase
|
||||||
|
# Passphrase for unlocking the private key
|
||||||
|
#
|
||||||
|
# @return [OpenSSL::PKey] The private key for signing assertions.
|
||||||
|
#
|
||||||
|
def self.load_from_pem(keyfile, passphrase)
|
||||||
|
load_key(keyfile, passphrase) do | content, passphrase|
|
||||||
|
OpenSSL::PKey::RSA.new(content, passphrase)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
##
|
||||||
|
# Helper for loading keys from file or memory. Accepts a block
|
||||||
|
# to handle the specific file format.
|
||||||
|
#
|
||||||
|
# @param [String] keyfile
|
||||||
|
# Path of thefile to load. If not a path to an actual file,
|
||||||
|
# assumes the string is the content of the file itself.
|
||||||
|
# @param [String] passphrase
|
||||||
|
# Passphrase for unlocking the private key
|
||||||
|
#
|
||||||
|
# @yield [String, String]
|
||||||
|
# Key file & passphrase to extract key from
|
||||||
|
# @yieldparam [String] keyfile
|
||||||
|
# Contents of the file
|
||||||
|
# @yieldparam [String] passphrase
|
||||||
|
# Passphrase to unlock key
|
||||||
|
# @yieldreturn [OpenSSL::PKey]
|
||||||
|
# Private key
|
||||||
|
#
|
||||||
|
# @return [OpenSSL::PKey] The private key for signing assertions.
|
||||||
|
def self.load_key(keyfile, passphrase, &block)
|
||||||
|
begin
|
||||||
|
begin
|
||||||
|
content = File.read(keyfile)
|
||||||
|
rescue
|
||||||
|
content = keyfile
|
||||||
|
end
|
||||||
|
block.call(content, passphrase)
|
||||||
|
rescue OpenSSL::OpenSSLError
|
||||||
|
raise ArgumentError.new("Invalid keyfile or passphrase")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,6 +12,7 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
require 'google/api_client/auth/key_utils'
|
||||||
module Google
|
module Google
|
||||||
class APIClient
|
class APIClient
|
||||||
##
|
##
|
||||||
|
@ -30,18 +31,10 @@ module Google
|
||||||
# Passphrase for unlocking the private key
|
# Passphrase for unlocking the private key
|
||||||
#
|
#
|
||||||
# @return [OpenSSL::PKey] The private key for signing assertions.
|
# @return [OpenSSL::PKey] The private key for signing assertions.
|
||||||
|
# @deprecated
|
||||||
|
# Use {Google::APIClient::KeyUtils} instead
|
||||||
def self.load_key(keyfile, passphrase)
|
def self.load_key(keyfile, passphrase)
|
||||||
begin
|
KeyUtils.load_from_pkcs12(keyfile, passphrase)
|
||||||
if File.exists?(keyfile)
|
|
||||||
content = File.read(keyfile)
|
|
||||||
else
|
|
||||||
content = keyfile
|
|
||||||
end
|
|
||||||
pkcs12 = OpenSSL::PKCS12.new(content, passphrase)
|
|
||||||
return pkcs12.key
|
|
||||||
rescue OpenSSL::PKCS12::PKCS12Error
|
|
||||||
raise ArgumentError.new("Invalid keyfile or passphrase")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,3 +14,4 @@
|
||||||
|
|
||||||
require 'google/api_client/auth/pkcs12'
|
require 'google/api_client/auth/pkcs12'
|
||||||
require 'google/api_client/auth/jwt_asserter'
|
require 'google/api_client/auth/jwt_asserter'
|
||||||
|
require 'google/api_client/auth/key_utils'
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,19 @@
|
||||||
|
Bag Attributes
|
||||||
|
friendlyName: privatekey
|
||||||
|
localKeyID: 54 69 6D 65 20 31 33 35 31 38 38 38 31 37 38 36 39 36
|
||||||
|
Key Attributes: <No Attributes>
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIICXAIBAAKBgQDYDyPb3GhyFx5i/wxS/jFsO6wSLys1ehAk6QZoBXGlg7ETVrIJ
|
||||||
|
HYh9gXQUno4tJiQoaO8wOvleIRrqI0LkiftCXKWVSrzOiV+O9GkKx1byw1yAIZus
|
||||||
|
QdwMT7X0O9hrZLZwhICWC9s6cGhnlCVxLIP/+JkVK7hxEq/LxoSszNV77wIDAQAB
|
||||||
|
AoGAa2G69L7quil7VMBmI6lqbtyJfNAsrXtpIq8eG/z4qsZ076ObAKTI/XeldcoH
|
||||||
|
57CZL+xXVKU64umZMt0rleJuGXdlauEUbsSx+biGewRfGTgC4rUSjmE539rBvmRW
|
||||||
|
gaKliorepPMp/+B9CcG/2YfDPRvG/2cgTXJHVvneo+xHL4ECQQD2Jx5Mvs8z7s2E
|
||||||
|
jY1mkpRKqh4Z7rlitkAwe1NXcVC8hz5ASu7ORyTl8EPpKAfRMYl1ofK/ozT1URXf
|
||||||
|
kL5nChPfAkEA4LPUJ6cqrY4xrrtdGaM4iGIxzen5aZlKz/YNlq5LuQKbnLLHMuXU
|
||||||
|
ohp/ynpqNWbcAFbmtGSMayxGKW5+fJgZ8QJAUBOZv82zCmn9YcnK3juBEmkVMcp/
|
||||||
|
dKVlbGAyVJgAc9RrY+78kQ6D6mmnLgpfwKYk2ae9mKo3aDbgrsIfrtWQcQJAfFGi
|
||||||
|
CEpJp3orbLQG319ZsMM7MOTJdC42oPZOMFbAWFzkAX88DKHx0bn9h+XQizkccSej
|
||||||
|
Ppz+v3DgZJ3YZ1Cz0QJBALiqIokZ+oa3AY6oT0aiec6txrGvNPPbwOsrBpFqGNbu
|
||||||
|
AByzWWBoBi40eKMSIR30LqN9H8YnJ91Aoy1njGYyQaw=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
|
@ -16,6 +16,37 @@ require 'spec_helper'
|
||||||
|
|
||||||
require 'google/api_client'
|
require 'google/api_client'
|
||||||
|
|
||||||
|
fixtures_path = File.expand_path('../../../fixtures', __FILE__)
|
||||||
|
|
||||||
|
describe Google::APIClient::KeyUtils do
|
||||||
|
it 'should read PKCS12 files from the filesystem' do
|
||||||
|
path = File.expand_path('files/privatekey.p12', fixtures_path)
|
||||||
|
key = Google::APIClient::KeyUtils.load_from_pkcs12(path, 'notasecret')
|
||||||
|
key.should_not == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should read PKCS12 files from loaded files' do
|
||||||
|
path = File.expand_path('files/privatekey.p12', fixtures_path)
|
||||||
|
content = File.read(path)
|
||||||
|
key = Google::APIClient::KeyUtils.load_from_pkcs12(content, 'notasecret')
|
||||||
|
key.should_not == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should read PEM files from the filesystem' do
|
||||||
|
path = File.expand_path('files/secret.pem', fixtures_path)
|
||||||
|
key = Google::APIClient::KeyUtils.load_from_pem(path, 'notasecret')
|
||||||
|
key.should_not == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should read PEM files from loaded files' do
|
||||||
|
path = File.expand_path('files/secret.pem', fixtures_path)
|
||||||
|
content = File.read(path)
|
||||||
|
key = Google::APIClient::KeyUtils.load_from_pem(content, 'notasecret')
|
||||||
|
key.should_not == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
describe Google::APIClient::JWTAsserter do
|
describe Google::APIClient::JWTAsserter do
|
||||||
include ConnectionHelpers
|
include ConnectionHelpers
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue