Class: FirebaseIdToken::Certificates

Inherits:
Object
  • Object
show all
Defined in:
lib/firebase_id_token/certificates.rb

Overview

Manage download and access of Google's x509 certificates. Keeps certificates on a Redis namespace database.

Download & Access Certificates

It describes two ways to download it: Certificates.request and Certificates.request!. The first will only do something when Redis certificates database 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 Redis expiration time to match Google's API header expires. After this time went out, Redis will automatically delete 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 Redis certificates database or Certificates.all to obtain an Array of current certificates.

Examples:

.request will only download once

FirebaseIdToken::Certificates.request # Downloads certificates.
FirebaseIdToken::Certificates.request # Won't do anything.
FirebaseIdToken::Certificates.request # Won't do anything either.

.request! will download always

FirebaseIdToken::Certificates.request # Downloads certificates.
FirebaseIdToken::Certificates.request! # Downloads certificates.
FirebaseIdToken::Certificates.request! # Downloads certificates.

Constant Summary collapse

URL =

Google's x509 certificates API URL.

'https://www.googleapis.com/robot/v1/metadata/x509/'\
'[email protected]'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCertificates

Sets two instance attributes: :redis and :local_certs. Those are respectively a Redis instance from FirebaseIdToken::Configuration and the certificates in it.



135
136
137
138
139
# File 'lib/firebase_id_token/certificates.rb', line 135

def initialize
  @redis = Redis::Namespace.new('firebase_id_token',
    redis: FirebaseIdToken.configuration.redis)
  @local_certs = read_certificates
end

Instance Attribute Details

#local_certsObject (readonly)

Certificates saved in the Redis (JSON String or nil).



36
37
38
# File 'lib/firebase_id_token/certificates.rb', line 36

def local_certs
  @local_certs
end

#redisObject (readonly)

A Redis instance.



34
35
36
# File 'lib/firebase_id_token/certificates.rb', line 34

def redis
  @redis
end

Class Method Details

.allArray

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 on Redis.

Examples:

FirebaseIdToken::Certificates.request
certs = FirebaseIdToken::Certificates.all
certs.first #=> {"1d6d01c7[...]" => #<OpenSSL::X509::Certificate[...]}

Returns:

  • (Array)


98
99
100
101
# File 'lib/firebase_id_token/certificates.rb', line 98

def self.all
  new.local_certs.map { |kid, cert|
    { kid => OpenSSL::X509::Certificate.new(cert) } }
end

.find(kid) ⇒ 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 Redis certificates database is empty.

Examples:

FirebaseIdToken::Certificates.request
cert = FirebaseIdToken::Certificates.find "1d6d01f4w7d54c7[...]"
#=> <OpenSSL::X509::Certificate: subject=#<OpenSSL [...]

Parameters:

  • kid (String)

    Key ID

Returns:

  • (nil, OpenSSL::X509::Certificate)

Raises:



114
115
116
117
118
119
120
121
# File 'lib/firebase_id_token/certificates.rb', line 114

def self.find(kid)
  certs = new.local_certs
  raise Exceptions::NoCertificatesError if certs.empty?

  if certs[kid]
    OpenSSL::X509::Certificate.new certs[kid]
  end
end

.present?Boolean

Returns true if there's certificates data on Redis, false otherwise.

Returns:

  • (Boolean)


84
85
86
# File 'lib/firebase_id_token/certificates.rb', line 84

def self.present?
  ! new.local_certs.empty?
end

.requestnil, Hash

Calls request! only if there are no certificates on Redis. 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.

Returns:

  • (nil, Hash)

See Also:



51
52
53
# File 'lib/firebase_id_token/certificates.rb', line 51

def self.request
  new.request
end

.request!Hash

Triggers a HTTPS request to Google's x509 certificates API. If it responds with a status 200 OK, saves the request body into Redis 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.

Returns:

  • (Hash)


65
66
67
# File 'lib/firebase_id_token/certificates.rb', line 65

def self.request!
  new.request!
end

.request_anywayObject

Deprecated.

Use only request! in favor of Ruby conventions.

It will raise a warning. Kept for compatibility.

See Also:



72
73
74
75
76
77
# File 'lib/firebase_id_token/certificates.rb', line 72

def self.request_anyway
  warn 'WARNING: FirebaseIdToken::Certificates.request_anyway is '\
    'deprecated. Use FirebaseIdToken::Certificates.request! instead.'

  new.request!
end

.ttlFixnum

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.

Returns:

  • (Fixnum)


127
128
129
130
# File 'lib/firebase_id_token/certificates.rb', line 127

def self.ttl
  ttl = new.redis.ttl('certificates')
  ttl < 0 ? 0 : ttl
end

Instance Method Details

#requestObject

See Also:



142
143
144
# File 'lib/firebase_id_token/certificates.rb', line 142

def request
  request! if @local_certs.empty?
end

#request!Object

See Also:



147
148
149
150
151
152
153
154
155
# File 'lib/firebase_id_token/certificates.rb', line 147

def request!
  @request = HTTParty.get URL
  code = @request.code
  if code == 200
    save_certificates
  else
    raise Exceptions::CertificatesRequestError.new(code)
  end
end