Class: Verikloak::Pundit::UserContext

Inherits:
Object
  • Object
show all
Defined in:
lib/verikloak/pundit/user_context.rb

Overview

Lightweight wrapper around Keycloak claims for Pundit policies.

Constant Summary collapse

CLAIM_SUB =

JWT claim keys used internally

'sub'
CLAIM_EMAIL =
'email'
CLAIM_PREFERRED_USERNAME =
'preferred_username'
CLAIM_RESOURCE_ACCESS =
'resource_access'
CLAIM_ROLES =
'roles'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(claims, resource_client: nil, config: nil) ⇒ UserContext

Create a new user context from JWT claims.

Parameters:

  • claims (Hash)

    JWT claims issued by Keycloak

  • resource_client (String) (defaults to: nil)

    default resource client name for resource roles

  • config (Verikloak::Pundit::Configuration) (defaults to: nil)

    configuration snapshot to use



23
24
25
26
27
# File 'lib/verikloak/pundit/user_context.rb', line 23

def initialize(claims, resource_client: nil, config: nil)
  @config = config || Verikloak::Pundit.config
  @claims = ClaimUtils.normalize(claims)
  @resource_client = (resource_client || @config.resource_client).to_s
end

Instance Attribute Details

#claimsObject (readonly)

Returns the value of attribute claims.



16
17
18
# File 'lib/verikloak/pundit/user_context.rb', line 16

def claims
  @claims
end

#configObject (readonly)

Returns the value of attribute config.



16
17
18
# File 'lib/verikloak/pundit/user_context.rb', line 16

def config
  @config
end

#resource_clientObject (readonly)

Returns the value of attribute resource_client.



16
17
18
# File 'lib/verikloak/pundit/user_context.rb', line 16

def resource_client
  @resource_client
end

Class Method Details

.from_env(env) ⇒ UserContext

Build a user context from Rack env using configured claims key.

Parameters:

  • env (Hash)

    Rack environment

Returns:



102
103
104
105
106
# File 'lib/verikloak/pundit/user_context.rb', line 102

def self.from_env(env)
  config = Verikloak::Pundit.config
  claims = env&.fetch(config.env_claims_key, nil)
  new(claims, config: config)
end

Instance Method Details

#emailString?

Email or preferred username from claims.

Returns:

  • (String, nil)


37
38
39
# File 'lib/verikloak/pundit/user_context.rb', line 37

def email
  claims[CLAIM_EMAIL] || claims[CLAIM_PREFERRED_USERNAME]
end

#has_permission?(perm) ⇒ Boolean

Check whether the user has a mapped permission.

Uses realm roles and resource roles depending on Configuration#permission_role_scope.

Parameters:

  • perm (String, Symbol)

    permission to check

Returns:

  • (Boolean)


94
95
96
# File 'lib/verikloak/pundit/user_context.rb', line 94

def has_permission?(perm) # rubocop:disable Naming/PredicatePrefix
  permission_set.include?(normalize_to_symbol(perm))
end

#has_role?(role) ⇒ Boolean

Check whether the user has a realm role.

Parameters:

  • role (String, Symbol)

Returns:

  • (Boolean)


66
67
68
# File 'lib/verikloak/pundit/user_context.rb', line 66

def has_role?(role) # rubocop:disable Naming/PredicatePrefix
  realm_roles.include?(role.to_s)
end

#in_group?(group) ⇒ Boolean

Alias to has_role? to align with group-based naming.

Parameters:

  • group (String, Symbol)

Returns:

  • (Boolean)


74
75
76
# File 'lib/verikloak/pundit/user_context.rb', line 74

def in_group?(group)
  has_role?(group)
end

#realm_rolesArray<String>

Realm-level roles from claims based on configuration path.

Returns:

  • (Array<String>)


43
44
45
46
47
48
# File 'lib/verikloak/pundit/user_context.rb', line 43

def realm_roles
  @realm_roles ||= begin
    path = resolve_path(config.realm_roles_path)
    extract_roles(path)
  end
end

#resource_role?(client, role) ⇒ Boolean

Check whether the user has a role for a specific resource client.

Parameters:

  • client (String, Symbol)
  • role (String, Symbol)

Returns:

  • (Boolean)


83
84
85
# File 'lib/verikloak/pundit/user_context.rb', line 83

def resource_role?(client, role)
  resource_roles(client).include?(role.to_s)
end

#resource_roles(client = resource_client) ⇒ Array<String>

Resource-level roles for a given client from claims based on configuration path.

Parameters:

  • client (String) (defaults to: resource_client)

    resource client id (defaults to configured resource_client)

Returns:

  • (Array<String>)


54
55
56
57
58
59
60
# File 'lib/verikloak/pundit/user_context.rb', line 54

def resource_roles(client = resource_client)
  client = client.to_s
  (@resource_roles_cache ||= {})[client] ||= begin
    path = resolve_path(config.resource_roles_path, client: client)
    extract_roles(path)
  end
end

#subString?

Subject identifier from claims.

Returns:

  • (String, nil)


31
32
33
# File 'lib/verikloak/pundit/user_context.rb', line 31

def sub
  claims[CLAIM_SUB]
end