Add OIDC fixes, add prefered_username, add application-user claims
This commit is contained in:
35
app/services/concerns/claims_merger.rb
Normal file
35
app/services/concerns/claims_merger.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
module ClaimsMerger
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# Deep merge claims, combining arrays instead of overwriting them
|
||||
# This ensures that array values (like roles) are combined across group/user/app claims
|
||||
#
|
||||
# Example:
|
||||
# base = { "roles" => ["user"], "level" => 1 }
|
||||
# incoming = { "roles" => ["admin"], "department" => "IT" }
|
||||
# deep_merge_claims(base, incoming)
|
||||
# # => { "roles" => ["user", "admin"], "level" => 1, "department" => "IT" }
|
||||
def deep_merge_claims(base, incoming)
|
||||
result = base.dup
|
||||
|
||||
incoming.each do |key, value|
|
||||
if result.key?(key)
|
||||
# If both values are arrays, combine them (union to avoid duplicates)
|
||||
if result[key].is_a?(Array) && value.is_a?(Array)
|
||||
result[key] = (result[key] + value).uniq
|
||||
# If both values are hashes, recursively merge them
|
||||
elsif result[key].is_a?(Hash) && value.is_a?(Hash)
|
||||
result[key] = deep_merge_claims(result[key], value)
|
||||
else
|
||||
# Otherwise, incoming value wins (override)
|
||||
result[key] = value
|
||||
end
|
||||
else
|
||||
# New key, just add it
|
||||
result[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,6 @@
|
||||
class OidcJwtService
|
||||
extend ClaimsMerger
|
||||
|
||||
class << self
|
||||
# Generate an ID token (JWT) for the user
|
||||
def generate_id_token(user, application, consent: nil, nonce: nil)
|
||||
@@ -17,7 +19,7 @@ class OidcJwtService
|
||||
iat: now,
|
||||
email: user.email_address,
|
||||
email_verified: true,
|
||||
preferred_username: user.email_address,
|
||||
preferred_username: user.username.presence || user.email_address,
|
||||
name: user.name.presence || user.email_address
|
||||
}
|
||||
|
||||
@@ -29,16 +31,16 @@ class OidcJwtService
|
||||
payload[:groups] = user.groups.pluck(:name)
|
||||
end
|
||||
|
||||
# Add admin claim if user is admin
|
||||
payload[:admin] = true if user.admin?
|
||||
|
||||
# Merge custom claims from groups
|
||||
# Merge custom claims from groups (arrays are combined, not overwritten)
|
||||
user.groups.each do |group|
|
||||
payload.merge!(group.parsed_custom_claims)
|
||||
payload = deep_merge_claims(payload, group.parsed_custom_claims)
|
||||
end
|
||||
|
||||
# Merge custom claims from user (overrides group claims)
|
||||
payload.merge!(user.parsed_custom_claims)
|
||||
# Merge custom claims from user (arrays are combined, other values override)
|
||||
payload = deep_merge_claims(payload, user.parsed_custom_claims)
|
||||
|
||||
# Merge app-specific custom claims (highest priority, arrays are combined)
|
||||
payload = deep_merge_claims(payload, application.custom_claims_for_user(user))
|
||||
|
||||
JWT.encode(payload, private_key, "RS256", { kid: key_id, typ: "JWT" })
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user