OpenID Conformance: Include all required scopes when profile is requested, even if they're empty
Some checks failed
CI / scan_ruby (push) Has been cancelled
CI / scan_js (push) Has been cancelled
CI / scan_container (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / system-test (push) Has been cancelled

This commit is contained in:
Dan Milne
2026-01-02 15:47:40 +11:00
parent b517ebe809
commit 182682024d
2 changed files with 39 additions and 4 deletions

View File

@@ -657,9 +657,28 @@ class OidcController < ApplicationController
end end
# Profile claims (only if 'profile' scope requested) # Profile claims (only if 'profile' scope requested)
# Per OIDC Core spec section 5.4, all profile claims SHOULD be returned
if requested_scopes.include?("profile") if requested_scopes.include?("profile")
claims[:preferred_username] = user.email_address # Use username if available, otherwise email as preferred_username
claims[:preferred_username] = user.username.presence || user.email_address
# Name: use stored name or fall back to email
claims[:name] = user.name.presence || user.email_address claims[:name] = user.name.presence || user.email_address
# Standard profile claims we don't store - set to nil (optional per spec)
claims[:given_name] = nil
claims[:family_name] = nil
claims[:middle_name] = nil
claims[:nickname] = nil
claims[:profile] = nil
claims[:picture] = nil
claims[:website] = nil
claims[:gender] = nil
claims[:birthdate] = nil
claims[:zoneinfo] = nil
claims[:locale] = nil
# Time the user's information was last updated
claims[:updated_at] = user.updated_at.to_i
end end
# Groups claim (only if 'groups' scope requested) # Groups claim (only if 'groups' scope requested)

View File

@@ -115,9 +115,25 @@ class OidcUserinfoControllerTest < ActionDispatch::IntegrationTest
# Required claims # Required claims
assert json["sub"].present? assert json["sub"].present?
# Profile claims should be present # All standard profile claims should be present (per OIDC Core spec section 5.4)
assert_equal @user.email_address, json["preferred_username"], "Should include preferred_username with profile scope" # Some may be null if we don't have the data, but the keys should exist
assert json["name"].present?, "Should include name with profile scope" assert json.key?("name"), "Should include name claim"
assert json.key?("given_name"), "Should include given_name claim (may be null)"
assert json.key?("family_name"), "Should include family_name claim (may be null)"
assert json.key?("middle_name"), "Should include middle_name claim (may be null)"
assert json.key?("nickname"), "Should include nickname claim (may be null)"
assert json.key?("preferred_username"), "Should include preferred_username claim"
assert json.key?("profile"), "Should include profile claim (may be null)"
assert json.key?("picture"), "Should include picture claim (may be null)"
assert json.key?("website"), "Should include website claim (may be null)"
assert json.key?("gender"), "Should include gender claim (may be null)"
assert json.key?("birthdate"), "Should include birthdate claim (may be null)"
assert json.key?("zoneinfo"), "Should include zoneinfo claim (may be null)"
assert json.key?("locale"), "Should include locale claim (may be null)"
assert json.key?("updated_at"), "Should include updated_at claim"
# Verify preferred_username is using username or email
assert json["preferred_username"].present?, "preferred_username should have a value"
# Email claims should NOT be present # Email claims should NOT be present
assert_nil json["email"], "Should not include email without email scope" assert_nil json["email"], "Should not include email without email scope"