Class: LcpRuby::Authentication::UserResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/lcp_ruby/authentication/user_resolver.rb

Overview

Bridges OmniAuth’s auth_hash into an LCP user record. Called from the OIDC callback controller. Side-effects: may create a new LcpRuby::User, update fields on an existing one, and persist mapped roles.

Constant Summary collapse

PROTECTED_FIELDS =

Columns that update_on_login must never overwrite, regardless of what an ‘auth.yml` author lists. Devise-managed credentials, role/authorization state, the OIDC linkage keys, and audit columns are all out of bounds. The whitelist applied at runtime is `User.column_names - PROTECTED_FIELDS`.

%w[
  id provider external_id lcp_role active
  encrypted_password reset_password_token reset_password_sent_at
  remember_created_at sign_in_count current_sign_in_at last_sign_in_at
  current_sign_in_ip last_sign_in_ip failed_attempts unlock_token locked_at
  confirmation_token confirmed_at confirmation_sent_at unconfirmed_email
  created_at updated_at
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(auth:, provider:, claims: nil) ⇒ UserResolver

When ‘claims:` is non-nil, bypasses OmniAuth `auth_hash` extraction and uses the hash verbatim (after deep-stringification of keys). When nil, extracts claims from the OmniAuth hash (web-login path).



38
39
40
41
42
# File 'lib/lcp_ruby/authentication/user_resolver.rb', line 38

def initialize(auth:, provider:, claims: nil)
  @auth     = auth
  @provider = provider
  @claims   = claims.nil? ? extract_claims(auth) : claims.deep_stringify_keys
end

Class Method Details

.call(auth:, provider:) ⇒ Object



22
23
24
# File 'lib/lcp_ruby/authentication/user_resolver.rb', line 22

def self.call(auth:, provider:)
  new(auth: auth, provider: provider).call
end

.from_claims(claims:, provider:) ⇒ Object

Build a resolver from already-extracted claims (e.g. from a verified JWT) without an OmniAuth ‘auth_hash`. Reuses the provisioning, role mapping, and synchronizer pipeline. `auth` is nil for bearer flows; the `claims_synchronizer` hook receives nil as its 4th arg, so hosts that need the OmniAuth hash must guard.



31
32
33
# File 'lib/lcp_ruby/authentication/user_resolver.rb', line 31

def self.from_claims(claims:, provider:)
  new(auth: nil, provider: provider, claims: claims).call
end

Instance Method Details

#callObject



44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/lcp_ruby/authentication/user_resolver.rb', line 44

def call
  validate_claims!
  external_id = @claims[@provider.claim_mappings[:external_id].to_s]

  user = LcpRuby::User.find_by(provider: @provider.name, external_id: external_id)
  user ||= provision!(external_id)

  apply_updates!(user)
  user.lcp_role = RoleMapper.call(@claims, @provider)
  apply_claims_synchronizer!(user)
  user.active = true if user.respond_to?(:active=)
  user.save! if user.new_record? || user.changed? || attachment_changes?(user)
  user
end