Module: KeycloakApiRails::Testing

Defined in:
lib/keycloak-api-rails/testing.rb

Defined Under Namespace

Modules: Helpers Classes: PublicKeyResolver

Constant Summary collapse

KEY_SIZE =
2048
KEY_ID =
"keycloak-api-rails-testing"
ALGORITHM =
:RS256
DEFAULT_VALIDITY_IN_SECONDS =
3600
MONITOR =
Monitor.new

Class Method Summary collapse

Class Method Details

.auth_headers_for(**options) ⇒ Object

The 'Authorization' header a client would send, e.g. { "Authorization" => "Bearer eyJ0..." }. It accepts the same parameters as '.token_for'.



95
96
97
# File 'lib/keycloak-api-rails/testing.rb', line 95

def auth_headers_for(**options)
  { "Authorization" => "Bearer #{token_for(**options)}" }
end

.private_keyObject

The RSA key pair used to sign the tokens forged by this module. It is generated once per process: generating a key is by far the slowest operation of a test suite that uses tokens.



46
47
48
# File 'lib/keycloak-api-rails/testing.rb', line 46

def private_key
  MONITOR.synchronize { @private_key ||= OpenSSL::PKey::RSA.generate(KEY_SIZE) }
end

.public_keysObject



54
55
56
# File 'lib/keycloak-api-rails/testing.rb', line 54

def public_keys
  MONITOR.synchronize { @public_keys ||= JSON::JWK::Set.new(JSON::JWK.new(private_key.public_key, kid: KEY_ID)) }
end

.signing_keyObject



50
51
52
# File 'lib/keycloak-api-rails/testing.rb', line 50

def signing_key
  MONITOR.synchronize { @signing_key ||= JSON::JWK.new(private_key, kid: KEY_ID) }
end

.stub_public_keys!Object

Makes the library validate the tokens forged by this module. Assigning 'KeycloakApiRails.public_key_resolver = nil' restores the regular resolver.



60
61
62
# File 'lib/keycloak-api-rails/testing.rb', line 60

def stub_public_keys!
  KeycloakApiRails.public_key_resolver = PublicKeyResolver.new(public_keys)
end

.token_for(sub: SecureRandom.uuid, email: nil, locale: nil, authorized_party: nil, roles: [], resource_roles: {}, issued_at: Time.now, expires_at: nil, claims: {}) ⇒ Object

Forges a signed token, similar to the ones emitted by Keycloak. Every claim this library reads has a dedicated parameter; any other claim can be passed through 'claims', which is also how the attributes declared in 'config.custom_attributes' are set.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/keycloak-api-rails/testing.rb', line 67

def token_for(sub: SecureRandom.uuid,
              email: nil,
              locale: nil,
              authorized_party: nil,
              roles: [],
              resource_roles: {},
              issued_at: Time.now,
              expires_at: nil,
              claims: {})
  payload = {
    "sub"    => sub,
    "email"  => email,
    "locale" => locale,
    "azp"    => authorized_party,
    "iat"    => issued_at.to_i,
    "exp"    => (expires_at || (issued_at.to_i + DEFAULT_VALIDITY_IN_SECONDS)).to_i
  }.reject { |_, value| value.nil? }

  payload["realm_access"]    = { "roles" => roles.map(&:to_s) } unless roles.nil? || roles.empty?
  payload["resource_access"] = build_resource_access(resource_roles) unless resource_roles.nil? || resource_roles.empty?

  claims.each { |name, value| payload[name.to_s] = value }

  JSON::JWT.new(payload).sign(signing_key, ALGORITHM).to_s
end