lib/clarion/app.rb in clarion-0.3.0 vs lib/clarion/app.rb in clarion-1.0.0
- old
+ new
@@ -1,8 +1,7 @@
require 'erubis'
require 'sinatra/base'
-require 'u2f'
require 'securerandom'
require 'clarion/registrator'
require 'clarion/authenticator'
require 'clarion/authn'
@@ -54,14 +53,22 @@
def conf
context[:config]
end
- def u2f
- @u2f ||= U2F::U2F.new(conf.app_id || request.base_url)
+ def base_url
+ conf.app_id || request.base_url
end
+ def rp_id
+ conf.rp_id || request.host
+ end
+
+ def legacy_app_id
+ base_url
+ end
+
def counter
conf.counter
end
def store
@@ -69,12 +76,12 @@
end
def render_authn_json(authn)
{
authn: authn.as_json.merge(
- url: "#{request.base_url}/api/authn/#{authn.id}",
- html_url: "#{request.base_url}/authn/#{authn.id}",
+ url: "#{base_url}/api/authn/#{authn.id}",
+ html_url: "#{base_url}/authn/#{authn.id}",
)
}.to_json
end
end
@@ -95,16 +102,16 @@
end
if @authn.closed?
halt 410, "Authn already processed"
end
- authenticator = Authenticator.new(@authn, u2f, counter, store)
- @app_id, @requests, @challenge = authenticator.request
+ authenticator = Authenticator.new(@authn, counter, store, rp_id: rp_id, legacy_app_id: legacy_app_id)
+ @credential_request_options = authenticator.credential_request_options
@req_id = SecureRandom.urlsafe_base64(12)
session[:reqs] ||= {}
- session[:reqs][@req_id] = {challenge: @challenge}
+ session[:reqs][@req_id] = {challenge: authenticator.challenge}
erb :authn
end
## API (returns user-facing UI)
@@ -128,51 +135,64 @@
rescue OpenSSL::PKey::RSAError
halt 400, 'invalid public key'
end
@reg_id = SecureRandom.urlsafe_base64(12)
- registrator = Registrator.new(u2f, counter)
- @app_id, @requests = registrator.request
+ @name = params[:name]
+ # TODO: Give proper user_handle
+ registrator = Registrator.new(counter, rp_id: rp_id, rp_name: "Clarion: #{request.host}", display_name: @name)
+ @credential_creation_options = registrator.credential_creation_options
+
session[:regis] ||= []
session[:regis] << {
id: @reg_id,
- challenges: @requests.map(&:challenge),
+ challenge: registrator.challenge,
+ user_handle: registrator.user_handle,
key: public_key.to_der,
}
session[:regis].shift(session[:regis].size - 4) if session[:regis].size > 4
@callback = params[:callback]
@state = params[:state]
- @name = params[:name]
@comment = params[:comment]
erb :register
end
get '/register', ®ister
post '/register', ®ister
## Internal APIs (used from UI)
post '/ui/register' do
content_type :json
- unless data[:reg_id] && data[:response]
+ unless data[:reg_id] && data[:attestation_object] && data[:client_data_json]
halt 400, '{"error": "Missing params"}'
end
session[:regis] ||= []
reg = session[:regis].find { |_| _[:id] == data[:reg_id] }
- unless reg && reg[:challenges] && reg[:key]
+ unless reg && reg[:challenge] && reg[:user_handle] && reg[:key]
halt 400, '{"error": "Invalid :reg"}'
end
public_key = begin
OpenSSL::PKey::RSA.new(reg[:key], '') # der
rescue OpenSSL::PKey::RSAError
halt 400, '{"error": "Invalid public key"}'
end
- registrator = Registrator.new(u2f, counter)
- key = registrator.register!(reg[:challenges], data[:response])
+ registrator = Registrator.new(counter, rp_id: rp_id, user_handle: reg[:user_handle])
+ begin
+ key = registrator.register!(
+ challenge: reg[:challenge],
+ origin: request.base_url,
+ attestation_object: data[:attestation_object].unpack('m*')[0],
+ client_data_json: data[:client_data_json].unpack('m*')[0],
+ )
+ rescue Registrator::InvalidAttestation => e
+ logger.warn "invalid attestation error: #{e.inspect}"
+ halt 400, {user_error: true, error: "Invalid attestation"}.to_json
+ end
key.name = data[:name]
session[:regis].reject! { |_| _[:id] == data[:reg_id] }
{ok: true, name: key.name, encrypted_key: key.to_encrypted_json(public_key, :all)}.to_json
@@ -210,11 +230,11 @@
'{"ok": true}'
end
post '/ui/verify/:id' do
content_type :json
- unless data[:req_id] && data[:response]
+ unless data[:req_id] && data[:authenticator_data] && data[:client_data_json] && data[:signature] && data[:credential_id]
halt 400, '{"error": "missing params"}'
end
session[:reqs] ||= {}
unless session[:reqs][data[:req_id]]
halt 400, '{"error": "invalid :req_id"}'
@@ -233,21 +253,28 @@
end
if @authn.closed?
halt 410, '{"error": "authn already processed"}'
end
- authenticator = Authenticator.new(@authn, u2f, counter, store)
+ authenticator = Authenticator.new(@authn, counter, store, rp_id: rp_id, legacy_app_id: legacy_app_id)
begin
authenticator.verify!(
- challenge,
- data[:response]
+ challenge: challenge,
+ origin: request.base_url,
+ credential_id: data[:credential_id],
+ authenticator_data: data[:authenticator_data].unpack('m*')[0],
+ client_data_json: data[:client_data_json].unpack('m*')[0],
+ signature: data[:signature].unpack('m*')[0],
)
- rescue U2F::Error => e
- halt 400, {error: "U2F Error: #{e.message}"}.to_json
+ logger.info "authn verified (#{@authn.id}) with credential_id=#{data[:credential_id]}"
+ rescue Authenticator::InvalidAssertion => e
+ logger.warn "authn verify error (#{@authn.id}; credential_id=#{data[:credential_id]}): #{e.inspect}"
+ halt 400, {user_error: true, error: "Invalid assertion"}.to_json
rescue Authenticator::InvalidKey => e
- halt 400, {error: "It is an unregistered key"}.to_json
+ logger.warn "authn verify error (#{@authn.id}; credential_id=#{data[:credential_id]}): #{e.inspect}"
+ halt 401, {user_error: true, error: "It is an unregistered key"}.to_json
end
session[:reqs].delete data[:req_id]
'{"ok": true}'
end
@@ -284,10 +311,10 @@
get '/test' do
key = conf.options[:register_test_key] ||= OpenSSL::PKey::RSA.generate(2048)
@name = 'testuser'
@comment = 'test comment'
- @register_url = "#{request.base_url}/register"
+ @register_url = "#{base_url}/register"
@callback = "#{request.base_url}/test/callback"
@public_key = [key.public_key.to_der].pack('m*').gsub(/\r?\n/, '')
@state = SecureRandom.urlsafe_base64(12)
erb :test
end