95 lines
2.7 KiB
Ruby
95 lines
2.7 KiB
Ruby
#
|
|
# Copyright (C) 2018 - present Instructure, Inc.
|
|
#
|
|
# This file is part of Canvas.
|
|
#
|
|
# Canvas is free software: you can redistribute it and/or modify it under
|
|
# the terms of the GNU Affero General Public License as published by the Free
|
|
# Software Foundation, version 3 of the License.
|
|
#
|
|
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License along
|
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
module Lti
|
|
class KeyStorage
|
|
PAST = 'jwk-past.json'.freeze
|
|
PRESENT = 'jwk-present.json'.freeze
|
|
FUTURE = 'jwk-future.json'.freeze
|
|
LTI_KEYS = 'lti-keys'.freeze
|
|
class << self
|
|
# Retrieve the keys in JSON format
|
|
#
|
|
# @return [Hash] The hash of past, present, and future key
|
|
def retrieve_keys
|
|
{ PAST => get_key(PAST), PRESENT => get_key(PRESENT), FUTURE => get_key(FUTURE) }
|
|
end
|
|
|
|
# Rotate the keys
|
|
# The present key becomes the past key; the future key becomes
|
|
# present; and a newly generated key becomes the future one
|
|
def rotate_keys
|
|
keys = retrieve_keys
|
|
if keys.values.compact.blank?
|
|
initialize_keys
|
|
else
|
|
kvs = {
|
|
PAST => keys[PRESENT].to_json,
|
|
PRESENT => keys[FUTURE].to_json,
|
|
FUTURE => new_key
|
|
}
|
|
consul_proxy.set_keys(kvs, global: true)
|
|
end
|
|
Canvas::DynamicSettings.reset_cache!
|
|
end
|
|
|
|
# Retrieve the public keys in JWK format
|
|
#
|
|
# @return [Array] The array of public keys in JWK format
|
|
def public_keyset
|
|
retrieve_keys.values.map do |private_jwk|
|
|
public_jwk = private_jwk.to_key.public_key.to_jwk
|
|
public_jwk.merge(private_jwk.select{|k,_| %w(alg use kid).include?(k) })
|
|
end
|
|
end
|
|
|
|
# Retrieve the present key
|
|
#
|
|
# @return [JSON::JWK] the present private key
|
|
def present_key
|
|
JSON::JWK.new(Lti::KeyStorage.retrieve_keys[PRESENT])
|
|
end
|
|
|
|
private
|
|
|
|
def initialize_keys
|
|
if retrieve_keys.values.compact.blank?
|
|
kvs = {
|
|
PAST => new_key,
|
|
PRESENT => new_key,
|
|
FUTURE => new_key
|
|
}
|
|
consul_proxy.set_keys(kvs, global: true)
|
|
end
|
|
end
|
|
|
|
def get_key(key)
|
|
value = consul_proxy[key]
|
|
JSON::JWK.new(JSON.parse(value)) if value.present?
|
|
end
|
|
|
|
def consul_proxy
|
|
Canvas::DynamicSettings.kv_proxy(LTI_KEYS, tree: :store)
|
|
end
|
|
|
|
def new_key
|
|
Lti::RSAKeyPair.new.to_jwk.to_json
|
|
end
|
|
end
|
|
end
|
|
end
|