class OmniAuth::Globalid::Vault

Attributes

openid_token[RW]
private_key[RW]

Public Class Methods

new(openid_token: nil, token_url: nil, client_id: nil, client_secret: nil, redirect_uri: nil, private_key: nil, private_key_pass: nil, acrc_id: nil) click to toggle source
# File lib/omniauth/globalid/vault.rb, line 6
def initialize(openid_token: nil, token_url: nil, client_id: nil, client_secret: nil,
               redirect_uri: nil, private_key: nil, private_key_pass: nil, acrc_id: nil)
  @openid_token = openid_token
  # TODO: Figure out a cleaner way to implement this!
  @token_url = token_url || "https://api.global.id/v1/auth/token"
  @client_id = client_id || ENV["GLOBALID_CLIENT_ID"]
  @client_secret = client_secret || ENV["GLOBALID_CLIENT_SECRET"]
  @redirect_uri = redirect_uri || ENV["GLOBALID_REDIRECT_URL"]
  @acrc_id = acrc_id || ENV["ACRC_ID"]
  # Clean up the private key in case environmental variables were extra escaped
  private_key ||= ENV["GLOBALID_PRIVATE_KEY"].gsub("\\n", "\n").gsub("\"", "")
  private_key_pass ||= ENV["GLOBALID_PRIVATE_KEY_PASS"]
  @private_key = OpenSSL::PKey::RSA.new(private_key, private_key_pass)
end

Public Instance Methods

client_credentials_access_token() click to toggle source
# File lib/omniauth/globalid/vault.rb, line 59
def client_credentials_access_token
  # TODO: figure out how to configure these without having to specify via environmental variables
  client_credentials_token_params = {
    client_id: @client_id,
    client_secret: @client_secret,
    redirect_uri: @redirect_uri,
    grant_type: "client_credentials",
    acrc_id: @acrc_id
  }
  client_credentials_response = Faraday.new(url: @token_url).post do |req|
    req.headers["Content-Type"] = "application/json"
    req.body = client_credentials_token_params.to_json
  end
  JSON.parse(client_credentials_response.body)["access_token"] # this is the only part of the client_credentials_response we use
end
decrypted_pii() click to toggle source
# File lib/omniauth/globalid/vault.rb, line 23
def decrypted_pii
  vault_response.map do |vault_data|
    # Decrypt the password for the vault data
    decrypted_data_password = private_key.private_decrypt(Base64.decode64(vault_data["encrypted_data_password"]), OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
    # The Initialization Vector is the first 32 bytes of the encrypted data
    iv = vault_data["encrypted_data"][0, 32]
    # The actual encrypted data is everything after the first 32 bytes
    encrypted_data = vault_data["encrypted_data"][32, vault_data["encrypted_data"].length]
    # Create a cipher that can decrypt the data that was encrypted in the vault
    cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
    cipher.decrypt # Tell the cipher instance that we are going to decrypt with it
    # The password and the IV are hex encoded
    cipher.key = Array(decrypted_data_password).pack("H*") # Encode the password in hex (base16)
    cipher.iv = Array(iv).pack("H*") # the initialization vector (iv) is first 32 chars of the encoded_data, hex encoded
    # Decode the base64 encoded data, and decrypt it!
    decrypted_pii = cipher.update(Base64.decode64(encrypted_data)) + cipher.final
    JSON.parse(decrypted_pii)
  end
end
decrypted_tokens() click to toggle source
# File lib/omniauth/globalid/vault.rb, line 51
def decrypted_tokens
  # Get the tokens to make requests to the vault, which is how you access the PII, by decrypting the encrypted_data_tokens
  encrypted_data_tokens.map do |claim_token|
    # The claim_tokens are base64 encoded
    private_key.private_decrypt(Base64.decode64(claim_token), OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
  end
end
encrypted_data_tokens() click to toggle source
# File lib/omniauth/globalid/vault.rb, line 43
def encrypted_data_tokens
  # Parsing this is a paid because the keys are dynamic
  # And we need the inside of the nested structure :(
  @openid_token.select { |k, v| k.match?("/claims/") }
    .reject { |k, v| k.match?("/claims/null") }
    .values.map(&:values).flatten
end
vault_response() click to toggle source
# File lib/omniauth/globalid/vault.rb, line 75
def vault_response
  result = Faraday.new(url: "https://api.global.id/v1/vault/get-encrypted-data").post do |req|
    req.headers["Authorization"] = "Bearer #{client_credentials_access_token}"
    req.headers["Content-Type"] = "application/json"
    req.body = { private_data_tokens: decrypted_tokens }.to_json
  end
  JSON.parse(result.body)
end