Skip to content

Commit

Permalink
authentication functionality implemented, needs more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
LeKristapino committed Mar 4, 2020
1 parent d8d12f2 commit 6b8854c
Show file tree
Hide file tree
Showing 24 changed files with 451 additions and 195 deletions.
104 changes: 0 additions & 104 deletions .byebug_history

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@

# rspec failure tracking
.rspec_status
.byebug_history
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/smart_id`. To experiment with that code, run `bin/console` for an interactive prompt.

TODO: Delete this and the text above, and describe your gem

## TODO
Verify that the X.509 certificate of the HTTPS endpoint is valid (not expired, signed by trusted CA and not revoked) These checks are incorporated into:
## Installation

Add this line to your application's Gemfile:
Expand Down
25 changes: 14 additions & 11 deletions lib/smart_id.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
require "smart_id/version"
require "smart_id/utils/authentication_hash"
require "smart_id/utils/certificate_validator"
require "smart_id/utils/verification_code_calculator"
require "smart_id/api/request"
require "smart_id/api/response"
require "smart_id/api/confirmation_response"
require "smart_id/api/authentication/identity_number"
require "smart_id/api/authentication/document"
require "smart_id/api/authentication/confirmation_poller"
require "smart_id/authentication_certificate/certificate"
require "smart_id/authentication_certificate/content"

module SmartId
@@environment = "DEMO" # possible options are demo and production
@@relying_party_uuid = nil
@@relying_party_name = nil
@@default_certificate_level = "QUALIFIED"
@@host_url = nil
@@smart_id_base_url = "https://sid.demo.sk.ee/smart-id-rp/v1/"
@@default_certificate_level = "ADVANCED" # possible values are "ADVANCED", "QUALIFIED"
@@poller_timeout_seconds = 10

def self.configure(&block)
Expand Down Expand Up @@ -43,19 +46,19 @@ def self.default_certificate_level
@@default_certificate_level
end

def self.smart_id_base_url=(value)
@@smart_id_base_url = value
end

def self.smart_id_base_url
@@smart_id_base_url
end

def self.poller_timeout_seconds=(value)
@@poller_timeout_seconds = value
end

def self.poller_timeout_seconds
@@poller_timeout_seconds
end

def self.environment=(value)
@@environment = value.upcase
end

def self.environment
@@environment
end
end
25 changes: 5 additions & 20 deletions lib/smart_id/api/authentication/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,16 @@ def self.authenticate(**opts)
end

def initialize(**opts)
@authentication_hash = SmartId::Utils::AuthenticationHash.new(opts[:hashable_data])
@authentication_hash = opts[:authentication_hash]
@display_text = opts[:display_text]
@nonce = opts[:nonce]
@certificate_level = opts[:certificate_level]
end


def call
begin
request = RestClient::Request.execute(
method: :post,
url: api_url,
payload: JSON.generate(request_params),
headers: { content_type: :json, accept: :json }
)
SmartId::Api::Response.new(JSON.parse(request.body), @authentication_hash)

rescue RestClient::RequestFailed => e
case e.http_code
when 471
raise SmartId::IncorrectAccountLevelError
else
raise SmartId::ConnectionError
end
end
response = SmartId::Api::Request.execute(method: :post, uri: api_uri, params: request_params)
SmartId::Api::Response.new(JSON.parse(response.body), authentication_hash)
end

private
Expand All @@ -48,7 +33,7 @@ def request_params
relyingPartyUUID: SmartId.relying_party_uuid,
relyingPartyName: SmartId.relying_party_name,
certificateLevel: @certificate_level || SmartId.default_certificate_level,
hash: @authentication_hash.calculate_base64_digest,
hash: authentication_hash.calculate_base64_digest,
hashType: "SHA256"
}

Expand All @@ -63,7 +48,7 @@ def request_params
params
end

def api_url
def api_uri
raise NotImplementedError
end
end
Expand Down
54 changes: 19 additions & 35 deletions lib/smart_id/api/authentication/confirmation_poller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,33 @@ module Authentication
class ConfirmationPoller
BASE_URI = "session/"

def self.confirm(session_id)
new(session_id).call
def self.confirm(session_id, authentication_hash)
new(session_id, authentication_hash).call

end

def initialize(session_id)
def initialize(session_id, authentication_hash)
@session_id = session_id
@authentication_hash = authentication_hash
end

def call
begin
request = RestClient::Request.execute(
method: :get,
url: api_url,
headers: {
accept: :json,
params: { timeoutMs: SmartId.poller_timeout_seconds * 1000}
},
timeout: SmartId.poller_timeout_seconds + 1 # Add an extra second before request times out
)

response = ConfirmationResponse.new(JSON.parse(request.body))

# repeat request if confirmation is still running
if response.confirmation_running?
call
else
response
end

rescue RestClient::RequestFailed => e
case e.http_code
when 471
raise SmartId::IncorrectAccountLevelError
else
raise SmartId::ConnectionError
end
end
end
params = { timeoutMs: SmartId.poller_timeout_seconds * 1000 }
uri = BASE_URI + @session_id

private
raw_response = SmartId::Api::Request.execute(method: :get, uri: uri, params: params)

response = SmartId::Api::ConfirmationResponse.new(
JSON.parse(raw_response.body),
@authentication_hash.hash_data
)

def api_url
SmartId.smart_id_base_url + BASE_URI + @session_id
# repeat request if confirmation is still running
if response.confirmation_running?
call
else
response
end
end
end
end
Expand Down
5 changes: 2 additions & 3 deletions lib/smart_id/api/authentication/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ class Document < Base

def initialize(**opts)
@document_number = opts[:document_number]

super(**opts)
end

private

def api_url
SmartId.smart_id_base_url + "#{BASE_URI}/#{@document_number}"
def api_uri
"#{BASE_URI}/#{@document_number}"
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/smart_id/api/authentication/identity_number.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ def initialize(**opts)

private

def api_url
SmartId.smart_id_base_url + "#{BASE_URI}/#{@country}/#{@identity_number}"
def api_uri
"#{BASE_URI}/#{@country}/#{@identity_number}"
end
end
end
Expand Down
19 changes: 13 additions & 6 deletions lib/smart_id/api/confirmation_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ class ConfirmationResponse

attr_reader :body

def initialize(response_body)
def initialize(response_body, hashed_data)
@body = response_body
end

def state
@body["state"]
validate!(hashed_data)
end

def confirmation_complete?
Expand All @@ -21,6 +18,10 @@ def confirmation_running?
state == RUNNING_STATE
end

def state
@body["state"]
end

def end_result
@body.dig("result", "endResult")
end
Expand All @@ -34,7 +35,7 @@ def certificate_level
end

def certificate
@body.dig("cert", "value")
@certificate ||= SmartId::AuthenticationCertificate::Certificate.new(@body.dig("cert", "value"))
end

def signature_algorithm
Expand All @@ -48,5 +49,11 @@ def signature
def ignored_properties
@body["ignoredProperties"]
end

private

def validate!(hashed_data)
SmartId::Utils::CertificateValidator.validate!(hashed_data, signature, certificate)
end
end
end
Loading

0 comments on commit 6b8854c

Please sign in to comment.