Class: FirebaseIdToken::Certificates
- Inherits:
-
Object
- Object
- FirebaseIdToken::Certificates
- Defined in:
- lib/firebase_id_token/certificates.rb
Overview
Manage download and access of Google's x509 certificates. Keeps certificates on an ActiveSupport cache.
Download & Access Certificates
It describes two ways to download it: Certificates.request and Certificates.request!. The first will only do something when the certificates cache is empty, the second one will always request a new download to Google's API and override the database with the response.
It's important to note that when saving a set of certificates, it will also
set a expiration time to match Google's API header expires. After
this time went out, the cache will no longer provide those certificates.
To know how many seconds left until the expiration you can use Certificates.ttl.
When comes to accessing it, you can either use Certificates.present? to check if
there's any data inside the cache or Certificates.all to obtain an
Array of current certificates.
Defined Under Namespace
Classes: ActiveSupport, Redis
Constant Summary collapse
- URL =
Google's x509 certificates API URL for ID Tokens.
'https://www.googleapis.com/robot/v1/metadata/x509/'\ 'securetoken@system.gserviceaccount.com'
- SESSION_COOKIE_URL =
Google's x509 certificates API URL for Session Cookies. Session Cookies are signed by a different key set than ID Tokens.
'https://www.googleapis.com/identitytoolkit/v3/'\ 'relyingparty/publicKeys'
- URLS =
Certificates API URL of each source.
{ id_token: URL, session_cookie: SESSION_COOKIE_URL }.freeze
- CACHE_KEYS =
Cache key of each source, so both certificate sets live side by side.
{ id_token: 'certificates', session_cookie: 'session_cookie_certificates' }.freeze
Instance Attribute Summary collapse
-
#local_certs ⇒ Object
readonly
Certificates saved in the cache (JSON
Stringornil). -
#source ⇒ Object
readonly
Certificate source (
:id_tokenor:session_cookie).
Class Method Summary collapse
-
.all(source: :id_token) ⇒ Array
Returns an array of hashes, each hash is a single
{key => value}pair containing the certificate KIDStringas key and aOpenSSL::X509::Certificateobject of the respective certificate as value. -
.find(kid, raise_error: false, source: :id_token) ⇒ nil, OpenSSL::X509::Certificate
Returns a
OpenSSL::X509::Certificateobject of the requested Key ID (KID) if there's one. -
.find!(kid, source: :id_token) ⇒ OpenSSL::X509::Certificate
Returns a
OpenSSL::X509::Certificateobject of the requested Key ID (KID) if there's one. -
.new_child(source: :id_token) ⇒ Object
When called on Certificates itself, picks the store class from the configuration.
-
.present?(source: :id_token) ⇒ Boolean
Returns
trueif there's certificates data in the cache,falseotherwise. -
.request(source: :id_token) ⇒ nil, Hash
Calls Certificates.request! only if there are no certificates in the cache.
-
.request!(source: :id_token) ⇒ Hash
Triggers a HTTPS request to Google's x509 certificates API.
-
.request_anyway ⇒ Object
deprecated
Deprecated.
Use only
request!in favor of Ruby conventions. -
.ttl(source: :id_token) ⇒ Fixnum
Returns the current certificates TTL (Time-To-Live) in seconds.
Instance Method Summary collapse
-
#initialize(source: :id_token) ⇒ Certificates
constructor
Sets two instance attributes:
:cach_storeand:local_certs. - #request ⇒ Object
- #request! ⇒ Object
Constructor Details
#initialize(source: :id_token) ⇒ Certificates
Sets two instance attributes: :cach_store and :local_certs. Those are
respectively a cache instance from FirebaseIdToken::Configuration and
the certificates in it.
181 182 183 184 |
# File 'lib/firebase_id_token/certificates.rb', line 181 def initialize(source: :id_token) # this should not be called directly. Call a child class raise NotImplementedError end |
Instance Attribute Details
#local_certs ⇒ Object (readonly)
Certificates saved in the cache (JSON String or nil).
34 35 36 |
# File 'lib/firebase_id_token/certificates.rb', line 34 def local_certs @local_certs end |
#source ⇒ Object (readonly)
Certificate source (:id_token or :session_cookie).
37 38 39 |
# File 'lib/firebase_id_token/certificates.rb', line 37 def source @source end |
Class Method Details
.all(source: :id_token) ⇒ Array
Returns an array of hashes, each hash is a single {key => value} pair
containing the certificate KID String as key and a
OpenSSL::X509::Certificate object of the respective certificate as
value. Returns a empty Array when there's no certificates data in
the cache.
115 116 117 118 |
# File 'lib/firebase_id_token/certificates.rb', line 115 def self.all(source: :id_token) new_child(source: source).local_certs.map { |kid, cert| { kid => OpenSSL::X509::Certificate.new(cert) } } end |
.find(kid, raise_error: false, source: :id_token) ⇒ nil, OpenSSL::X509::Certificate
Returns a OpenSSL::X509::Certificate object of the requested Key ID
(KID) if there's one. Returns nil otherwise.
It will raise a Exceptions::NoCertificatesError if the certificates cache is empty.
131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/firebase_id_token/certificates.rb', line 131 def self.find(kid, raise_error: false, source: :id_token) certs = new_child(source: source).local_certs raise Exceptions::NoCertificatesError if certs.empty? return OpenSSL::X509::Certificate.new certs[kid] if certs[kid] return unless raise_error raise Exceptions::CertificateNotFound, "Unable to find a certificate with `#{kid}`." end |
.find!(kid, source: :id_token) ⇒ OpenSSL::X509::Certificate
Returns a OpenSSL::X509::Certificate object of the requested Key ID
(KID) if there's one.
is empty.
157 158 159 |
# File 'lib/firebase_id_token/certificates.rb', line 157 def self.find!(kid, source: :id_token) find(kid, raise_error: true, source: source) end |
.new_child(source: :id_token) ⇒ Object
When called on Certificates itself, picks the store class from the configuration. When called on a subclass, instantiates that subclass.
172 173 174 175 176 |
# File 'lib/firebase_id_token/certificates.rb', line 172 def self.new_child(source: :id_token) return new(source: source) unless self == Certificates FirebaseIdToken.configuration.klass.new(source: source) end |
.present?(source: :id_token) ⇒ Boolean
Returns true if there's certificates data in the cache, false otherwise.
101 102 103 |
# File 'lib/firebase_id_token/certificates.rb', line 101 def self.present?(source: :id_token) ! new_child(source: source).local_certs.empty? end |
.request(source: :id_token) ⇒ nil, Hash
Calls request! only if there are no certificates in the cache. It will
return nil otherwise.
It will raise Exceptions::CertificatesRequestError if the request fails or Exceptions::CertificatesTtlError when Google responds with a low TTL, check out request! for more info.
67 68 69 |
# File 'lib/firebase_id_token/certificates.rb', line 67 def self.request(source: :id_token) new_child(source: source).request end |
.request!(source: :id_token) ⇒ Hash
Triggers a HTTPS request to Google's x509 certificates API. If it
responds with a status 200 OK, saves the request body into the cache and
returns it as a Hash.
Otherwise it will raise a Exceptions::CertificatesRequestError.
This is really rare to happen, but Google may respond with a low TTL
certificate. This is a SecurityError and will raise a
Exceptions::CertificatesTtlError. You are mostly like to never face it.
82 83 84 |
# File 'lib/firebase_id_token/certificates.rb', line 82 def self.request!(source: :id_token) new_child(source: source).request! end |
.request_anyway ⇒ Object
Use only request! in favor of Ruby conventions.
It will raise a warning. Kept for compatibility.
89 90 91 92 93 94 |
# File 'lib/firebase_id_token/certificates.rb', line 89 def self.request_anyway warn 'WARNING: FirebaseIdToken::Certificates.request_anyway is '\ 'deprecated. Use FirebaseIdToken::Certificates.request! instead.' new_child.request! end |
.ttl(source: :id_token) ⇒ Fixnum
Returns the current certificates TTL (Time-To-Live) in seconds. Zero meaning no certificates. It's the same as the certificates expiration time, use it to know when to request again.
165 166 167 168 |
# File 'lib/firebase_id_token/certificates.rb', line 165 def self.ttl(source: :id_token) # call a child class based on the configuration FirebaseIdToken.configuration.klass.ttl(source: source) end |
Instance Method Details
#request ⇒ Object
187 188 189 |
# File 'lib/firebase_id_token/certificates.rb', line 187 def request request! if @local_certs.empty? end |
#request! ⇒ Object
192 193 194 195 196 197 198 199 200 |
# File 'lib/firebase_id_token/certificates.rb', line 192 def request! @request = HTTParty.get URLS.fetch(@source) code = @request.code if code == 200 save_certificates else raise Exceptions::CertificatesRequestError.new(code) end end |