Move JWKs files to database
This commit is contained in:
parent
2c7d102019
commit
9c9880d880
12 changed files with 49 additions and 39 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -21,7 +21,6 @@ config/database.yml
|
|||
.rvmrc_custom
|
||||
.rvmrc.local
|
||||
config/oidc_key.pem
|
||||
config/jwks/
|
||||
|
||||
# Mailing list stuff
|
||||
config/email_offset
|
||||
|
|
|
|||
|
|
@ -10,12 +10,7 @@ module Api
|
|||
|
||||
def new
|
||||
auth = Api::OpenidConnect::Authorization.find_by_client_id_and_user(params[:client_id], current_user)
|
||||
if auth
|
||||
auth.o_auth_access_tokens.destroy_all
|
||||
auth.id_tokens.destroy_all
|
||||
auth.code_used = false
|
||||
auth.save
|
||||
end
|
||||
reset_auth(auth)
|
||||
if logged_in_before?(params[:max_age])
|
||||
reauthenticate
|
||||
elsif params[:prompt]
|
||||
|
|
@ -43,6 +38,14 @@ module Api
|
|||
|
||||
private
|
||||
|
||||
def reset_auth(auth)
|
||||
return unless auth
|
||||
auth.o_auth_access_tokens.destroy_all
|
||||
auth.id_tokens.destroy_all
|
||||
auth.code_used = false
|
||||
auth.save
|
||||
end
|
||||
|
||||
def handle_prompt(prompt, auth)
|
||||
if prompt.include? "select_account"
|
||||
handle_prompt_params_error("account_selection_required",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module Api
|
|||
if req["client_assertion_type"] == "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
|
||||
handle_jwt_bearer(req)
|
||||
end
|
||||
self.status, self.response.headers, self.response_body = Api::OpenidConnect::TokenEndpoint.new.call(request.env)
|
||||
self.status, response.headers, self.response_body = Api::OpenidConnect::TokenEndpoint.new.call(request.env)
|
||||
nil
|
||||
end
|
||||
|
||||
|
|
@ -24,12 +24,10 @@ module Api
|
|||
end
|
||||
|
||||
def fetch_public_key(o_auth_app, jwt)
|
||||
jwks_file_path = File.join(Rails.root, "config", "jwks", o_auth_app.jwks_file)
|
||||
public_key = fetch_public_key_from_json(File.read(jwks_file_path), jwt)
|
||||
public_key = fetch_public_key_from_json(o_auth_app.jwks, jwt)
|
||||
if public_key.empty? && o_auth_app.jwks_uri
|
||||
uri = URI.parse(o_auth_app.jwks_uri)
|
||||
response = Net::HTTP.get_response(uri)
|
||||
File.write jwks_file_path, response.body
|
||||
public_key = fetch_public_key_from_json(response.body, jwt)
|
||||
end
|
||||
raise Rack::OAuth2::Server::Authorize::BadRequest(:unauthorized_client) if public_key.empty?
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ module Api
|
|||
validates :client_secret, presence: true
|
||||
validates :client_name, uniqueness: {scope: :redirect_uris}
|
||||
|
||||
%i(redirect_uris response_types grant_types contacts).each do |serializable|
|
||||
%i(redirect_uris response_types grant_types contacts jwks).each do |serializable|
|
||||
serialize serializable, JSON
|
||||
end
|
||||
|
||||
|
|
@ -82,27 +82,15 @@ module Api
|
|||
elsif key == :jwks_uri
|
||||
uri = URI.parse(value)
|
||||
response = Net::HTTP.get_response(uri)
|
||||
file_name = create_file_path(response.body)
|
||||
attr[:jwks_file] = file_name + ".json"
|
||||
attr[:jwks] = response.body
|
||||
attr[:jwks_uri] = value
|
||||
elsif key == :jwks
|
||||
file_name = create_file_path(value.to_json)
|
||||
attr[:jwks_file] = file_name + ".json"
|
||||
attr[:jwks] = value.to_json
|
||||
else
|
||||
attr[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_file_path(content)
|
||||
file_name = Base64.urlsafe_encode64(Digest::SHA256.base64digest(content))
|
||||
directory_name = File.join(Rails.root, "config", "jwks")
|
||||
Dir.mkdir(directory_name) unless File.exist?(directory_name)
|
||||
jwk_file_path = File.join(Rails.root, "config", "jwks", file_name + ".json")
|
||||
File.write jwk_file_path, content
|
||||
File.chmod(0600, jwk_file_path)
|
||||
file_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,9 +17,8 @@ class CreateOAuthApplications < ActiveRecord::Migration
|
|||
t.string :tos_uri
|
||||
t.string :sector_identifier_uri
|
||||
t.string :token_endpoint_auth_method
|
||||
t.text :jwks
|
||||
t.string :jwks_uri
|
||||
t.string :jwks_file
|
||||
|
||||
t.boolean :ppid, default: false
|
||||
|
||||
t.timestamps null: false
|
||||
|
|
|
|||
10
db/schema.rb
10
db/schema.rb
|
|
@ -281,7 +281,7 @@ ActiveRecord::Schema.define(version: 20150828132451) do
|
|||
t.string "redirect_uris", limit: 255
|
||||
t.string "response_types", limit: 255
|
||||
t.string "grant_types", limit: 255
|
||||
t.string "application_type", limit: 255, default: "web"
|
||||
t.string "application_type", limit: 255, default: "web"
|
||||
t.string "contacts", limit: 255
|
||||
t.string "logo_uri", limit: 255
|
||||
t.string "client_uri", limit: 255
|
||||
|
|
@ -289,11 +289,11 @@ ActiveRecord::Schema.define(version: 20150828132451) do
|
|||
t.string "tos_uri", limit: 255
|
||||
t.string "sector_identifier_uri", limit: 255
|
||||
t.string "token_endpoint_auth_method", limit: 255
|
||||
t.text "jwks", limit: 65535
|
||||
t.string "jwks_uri", limit: 255
|
||||
t.string "jwks_file", limit: 255
|
||||
t.boolean "ppid", default: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.boolean "ppid", default: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
add_index "o_auth_applications", ["client_id"], name: "index_o_auth_applications_on_client_id", unique: true, length: {"client_id"=>191}, using: :btree
|
||||
|
|
|
|||
1
spec/fixtures/client_assertion_with_nonexistent_client_id.txt
vendored
Normal file
1
spec/fixtures/client_assertion_with_nonexistent_client_id.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
eyJhbGciOiJSUzI1NiIsImtpZCI6ImExIn0.ewogIGF1ZDogWwogICAgaHR0cHM6Ly9rZW50c2hpa2FtYS5jb20vYXBpL29wZW5pZF9jb25uZWN0L2FjY2Vzc190b2tlbnMKICBdLAogIGlzczogMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2QsCiAganRpOiAwbWNycmVZSCwKICBleHA6IDE0NDMxNzA4OTEuMzk3NDU2LAogIGlhdDogMTQ0MzE3MDI5MS4zOTc0NTYsCiAgc3ViOiAxNGQ2OTJjZDUzZDljMWE5ZjQ2ZmQ2OWUwZTU3NDQzZAp9Cg.QJUR3SYFrEIlbfOKjO0NYInddklytbJ2LSWNpkQ1aNThgneDCVCjIYGCaL2C9Sw-GR8j7QSUsKOwBbjZMUmVPFTjsfB4wdgObbxVt1QAXwDjAXc5w1smOerRsoahZ4yKI1an6PTaFxMwnoXUQcBZTsOS6RgXOCPPPoxibxohxoehPLieM0l7LYcF5DQKg7fTxZYOpmtiP--nibJxomXdVQNLSnZuQwnyWtlp_gYmqrYMMN1LPSmNCgZMZZZIYttaaAIA96SylglqubowJRShtDO9rSvUz_sgeCo7qo5Bfb0B5n9_PtIlr1CZSVoHyYj2lVqQldx7fnGuqqQJCfDQog
|
||||
1
spec/fixtures/client_assertion_with_nonexistent_kid.txt
vendored
Normal file
1
spec/fixtures/client_assertion_with_nonexistent_kid.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
ewogIGFsZzogUlMyNTYsCiAga2lkOiBpbnZhbGlkX2tpZAp9Cg.eyJhdWQiOiBbImh0dHBzOi8va2VudHNoaWthbWEuY29tL2FwaS9vcGVuaWRfY29ubmVjdC9hY2Nlc3NfdG9rZW5zIl0sICJpc3MiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UiLCAianRpIjogIjBtY3JyZVlIIiwgImV4cCI6IDE0NDMxNzA4OTEuMzk3NDU2LCAiaWF0IjogMTQ0MzE3MDI5MS4zOTc0NTYsICJzdWIiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UifQ.
|
||||
1
spec/fixtures/client_assertion_with_tampered_sig.txt
vendored
Normal file
1
spec/fixtures/client_assertion_with_tampered_sig.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
eyJhbGciOiJSUzI1NiIsImtpZCI6ImExIn0.eyJhdWQiOiBbImh0dHBzOi8va2VudHNoaWthbWEuY29tL2FwaS9vcGVuaWRfY29ubmVjdC9hY2Nlc3NfdG9rZW5zIl0sICJpc3MiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UiLCAianRpIjogIjBtY3JyZVlIIiwgImV4cCI6IDE0NDMxNzA4OTEuMzk3NDU2LCAiaWF0IjogMTQ0MzE3MDI5MS4zOTc0NTYsICJzdWIiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UifQ.QJUR3SYFrEIlbfOKjO0NYInddklytbJ2LSWNpkQ1aNThgneDCVCjIYGCaL2C9Sw-GR8j7QSUsKOwBbjZMUmVPFTjsfB4wdgObbxVt1QAXwDjAXc5w1smOerRsoahZ4yKI1an6PTaFxMwnoXUQcBZTsOS6RgXOCPPPoxibxohxoehPLieM0l7LYcF5DQKg7fTxZYOpmtiP--nibJxomXdVQNLSnZuQwnyWtlp_gYmqrYMMN1LPSmNCgZMZZZIYttaaAIA96SylglqubowJRShtDO9rSvUz_sgeCo7qo5Bfb0B5n9_PtIlr1CZSVoHyYj2lVqQldx7fnGuqqQJCfDQoe
|
||||
1
spec/fixtures/valid_client_assertion.txt
vendored
Normal file
1
spec/fixtures/valid_client_assertion.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
eyJhbGciOiJSUzI1NiIsImtpZCI6ImExIn0.eyJhdWQiOiBbImh0dHBzOi8va2VudHNoaWthbWEuY29tL2FwaS9vcGVuaWRfY29ubmVjdC9hY2Nlc3NfdG9rZW5zIl0sICJpc3MiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UiLCAianRpIjogIjBtY3JyZVlIIiwgImV4cCI6IDE0NDMxNzA4OTEuMzk3NDU2LCAiaWF0IjogMTQ0MzE3MDI5MS4zOTc0NTYsICJzdWIiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UifQ.QJUR3SYFrEIlbfOKjO0NYInddklytbJ2LSWNpkQ1aNThgneDCVCjIYGCaL2C9Sw-GR8j7QSUsKOwBbjZMUmVPFTjsfB4wdgObbxVt1QAXwDjAXc5w1smOerRsoahZ4yKI1an6PTaFxMwnoXUQcBZTsOS6RgXOCPPPoxibxohxoehPLieM0l7LYcF5DQKg7fTxZYOpmtiP--nibJxomXdVQNLSnZuQwnyWtlp_gYmqrYMMN1LPSmNCgZMZZZIYttaaAIA96SylglqubowJRShtDO9rSvUz_sgeCo7qo5Bfb0B5n9_PtIlr1CZSVoHyYj2lVqQldx7fnGuqqQJCfDQog
|
||||
|
|
@ -10,7 +10,7 @@ describe Api::OpenidConnect::TokenEndpoint, type: :request do
|
|||
let!(:client_with_specific_id) { FactoryGirl.create(:o_auth_application_with_ppid_with_specific_id) }
|
||||
let!(:auth_with_specific_id) do
|
||||
client_with_specific_id.client_id = "14d692cd53d9c1a9f46fd69e0e57443e"
|
||||
client_with_specific_id.jwks_file = jwks_file_path
|
||||
client_with_specific_id.jwks = File.read(jwks_file_path)
|
||||
client_with_specific_id.save!
|
||||
Api::OpenidConnect::Authorization.find_or_create_by(
|
||||
o_auth_application: client_with_specific_id,
|
||||
|
|
@ -67,7 +67,7 @@ describe Api::OpenidConnect::TokenEndpoint, type: :request do
|
|||
post api_openid_connect_access_tokens_path, grant_type: "authorization_code",
|
||||
redirect_uri: "http://localhost:3000/", code: code_with_specific_id,
|
||||
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
|
||||
client_assertion: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImExIn0.eyJhdWQiOiBbImh0dHBzOi8va2VudHNoaWthbWEuY29tL2FwaS9vcGVuaWRfY29ubmVjdC9hY2Nlc3NfdG9rZW5zIl0sICJpc3MiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UiLCAianRpIjogIjBtY3JyZVlIIiwgImV4cCI6IDE0NDMxNzA4OTEuMzk3NDU2LCAiaWF0IjogMTQ0MzE3MDI5MS4zOTc0NTYsICJzdWIiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UifQ.QJUR3SYFrEIlbfOKjO0NYInddklytbJ2LSWNpkQ1aNThgneDCVCjIYGCaL2C9Sw-GR8j7QSUsKOwBbjZMUmVPFTjsfB4wdgObbxVt1QAXwDjAXc5w1smOerRsoahZ4yKI1an6PTaFxMwnoXUQcBZTsOS6RgXOCPPPoxibxohxoehPLieM0l7LYcF5DQKg7fTxZYOpmtiP--nibJxomXdVQNLSnZuQwnyWtlp_gYmqrYMMN1LPSmNCgZMZZZIYttaaAIA96SylglqubowJRShtDO9rSvUz_sgeCo7qo5Bfb0B5n9_PtIlr1CZSVoHyYj2lVqQldx7fnGuqqQJCfDQog"
|
||||
client_assertion: File.read(valid_client_assertion_path)
|
||||
end
|
||||
|
||||
it "should return a valid id token" do
|
||||
|
|
@ -125,7 +125,7 @@ describe Api::OpenidConnect::TokenEndpoint, type: :request do
|
|||
post api_openid_connect_access_tokens_path, grant_type: "authorization_code",
|
||||
redirect_uri: "http://localhost:3000/", code: code_with_specific_id,
|
||||
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
|
||||
client_assertion: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImExIn0.eyJhdWQiOiBbImh0dHBzOi8va2VudHNoaWthbWEuY29tL2FwaS9vcGVuaWRfY29ubmVjdC9hY2Nlc3NfdG9rZW5zIl0sICJpc3MiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UiLCAianRpIjogIjBtY3JyZVlIIiwgImV4cCI6IDE0NDMxNzA4OTEuMzk3NDU2LCAiaWF0IjogMTQ0MzE3MDI5MS4zOTc0NTYsICJzdWIiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UifQ.QJUR3SYFrEIlbfOKjO0NYInddklytbJ2LSWNpkQ1aNThgneDCVCjIYGCaL2C9Sw-GR8j7QSUsKOwBbjZMUmVPFTjsfB4wdgObbxVt1QAXwDjAXc5w1smOerRsoahZ4yKI1an6PTaFxMwnoXUQcBZTsOS6RgXOCPPPoxibxohxoehPLieM0l7LYcF5DQKg7fTxZYOpmtiP--nibJxomXdVQNLSnZuQwnyWtlp_gYmqrYMMN1LPSmNCgZMZZZIYttaaAIA96SylglqubowJRShtDO9rSvUz_sgeCo7qo5Bfb0B5n9_PtIlr1CZSVoHyYj2lVqQldx7fnGuqqQJCfDQoe"
|
||||
client_assertion: File.read(client_assertion_with_tampered_sig_path)
|
||||
end
|
||||
|
||||
it "should return an error" do
|
||||
|
|
@ -138,7 +138,7 @@ describe Api::OpenidConnect::TokenEndpoint, type: :request do
|
|||
post api_openid_connect_access_tokens_path, grant_type: "authorization_code",
|
||||
redirect_uri: "http://localhost:3000/", code: code_with_specific_id,
|
||||
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
|
||||
client_assertion: "ewogIGFsZzogUlMyNTYsCiAga2lkOiBpbnZhbGlkX2tpZAp9Cg.eyJhdWQiOiBbImh0dHBzOi8va2VudHNoaWthbWEuY29tL2FwaS9vcGVuaWRfY29ubmVjdC9hY2Nlc3NfdG9rZW5zIl0sICJpc3MiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UiLCAianRpIjogIjBtY3JyZVlIIiwgImV4cCI6IDE0NDMxNzA4OTEuMzk3NDU2LCAiaWF0IjogMTQ0MzE3MDI5MS4zOTc0NTYsICJzdWIiOiAiMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2UifQ."
|
||||
client_assertion: File.read(client_assertion_with_nonexistent_kid_path)
|
||||
end
|
||||
|
||||
it "should return an error" do
|
||||
|
|
@ -159,7 +159,7 @@ describe Api::OpenidConnect::TokenEndpoint, type: :request do
|
|||
post api_openid_connect_access_tokens_path, grant_type: "authorization_code",
|
||||
redirect_uri: "http://localhost:3000/", code: code_with_specific_id,
|
||||
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
|
||||
client_assertion: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImExIn0.ewogIGF1ZDogWwogICAgaHR0cHM6Ly9rZW50c2hpa2FtYS5jb20vYXBpL29wZW5pZF9jb25uZWN0L2FjY2Vzc190b2tlbnMKICBdLAogIGlzczogMTRkNjkyY2Q1M2Q5YzFhOWY0NmZkNjllMGU1NzQ0M2QsCiAganRpOiAwbWNycmVZSCwKICBleHA6IDE0NDMxNzA4OTEuMzk3NDU2LAogIGlhdDogMTQ0MzE3MDI5MS4zOTc0NTYsCiAgc3ViOiAxNGQ2OTJjZDUzZDljMWE5ZjQ2ZmQ2OWUwZTU3NDQzZAp9Cg.QJUR3SYFrEIlbfOKjO0NYInddklytbJ2LSWNpkQ1aNThgneDCVCjIYGCaL2C9Sw-GR8j7QSUsKOwBbjZMUmVPFTjsfB4wdgObbxVt1QAXwDjAXc5w1smOerRsoahZ4yKI1an6PTaFxMwnoXUQcBZTsOS6RgXOCPPPoxibxohxoehPLieM0l7LYcF5DQKg7fTxZYOpmtiP--nibJxomXdVQNLSnZuQwnyWtlp_gYmqrYMMN1LPSmNCgZMZZZIYttaaAIA96SylglqubowJRShtDO9rSvUz_sgeCo7qo5Bfb0B5n9_PtIlr1CZSVoHyYj2lVqQldx7fnGuqqQJCfDQog"
|
||||
client_assertion: File.read(client_assertion_with_nonexistent_client_id_path)
|
||||
end
|
||||
|
||||
it "should return an error" do
|
||||
|
|
|
|||
|
|
@ -60,7 +60,26 @@ def photo_fixture_name
|
|||
end
|
||||
|
||||
def jwks_file_path
|
||||
@jwks_file = "../../spec/fixtures/jwks.json"
|
||||
@jwks_file = File.join(File.dirname(__FILE__), "fixtures", "jwks.json")
|
||||
end
|
||||
|
||||
def valid_client_assertion_path
|
||||
@valid_client_assertion = File.join(File.dirname(__FILE__), "fixtures", "valid_client_assertion.txt")
|
||||
end
|
||||
|
||||
def client_assertion_with_tampered_sig_path
|
||||
@client_assertion_with_tampered_sig = File.join(File.dirname(__FILE__), "fixtures",
|
||||
"client_assertion_with_tampered_sig.txt")
|
||||
end
|
||||
|
||||
def client_assertion_with_nonexistent_kid_path
|
||||
@client_assertion_with_nonexistent_kid = File.join(File.dirname(__FILE__), "fixtures",
|
||||
"client_assertion_with_nonexistent_kid.txt")
|
||||
end
|
||||
|
||||
def client_assertion_with_nonexistent_client_id_path
|
||||
@client_assertion_with_nonexistent_client_id = File.join(File.dirname(__FILE__), "fixtures",
|
||||
"client_assertion_with_nonexistent_client_id.txt")
|
||||
end
|
||||
|
||||
# Force fixture rebuild
|
||||
|
|
|
|||
Loading…
Reference in a new issue