Add missing files, fix formatting
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-05 23:34:11 +11:00
parent 233fb723d5
commit 444ae6291c
5 changed files with 59 additions and 10 deletions

View File

@@ -422,7 +422,11 @@ class OidcController < ApplicationController
# Record user consent # Record user consent
requested_scopes = oauth_params["scope"].split(" ") requested_scopes = oauth_params["scope"].split(" ")
parsed_claims = JSON.parse(oauth_params["claims_requests"]) rescue {} parsed_claims = begin
JSON.parse(oauth_params["claims_requests"])
rescue
{}
end
consent = OidcUserConsent.find_or_initialize_by(user: user, application: application) consent = OidcUserConsent.find_or_initialize_by(user: user, application: application)
consent.scopes_granted = requested_scopes.join(" ") consent.scopes_granted = requested_scopes.join(" ")
@@ -1026,7 +1030,7 @@ class OidcController < ApplicationController
end end
# Validate code verifier format (per RFC 7636: [A-Za-z0-9\-._~], 43-128 characters) # Validate code verifier format (per RFC 7636: [A-Za-z0-9\-._~], 43-128 characters)
unless code_verifier.match?(/\A[A-Za-z0-9\.\-_~]{43,128}\z/) unless code_verifier.match?(/\A[A-Za-z0-9.\-_~]{43,128}\z/)
return { return {
valid: false, valid: false,
error: "invalid_request", error: "invalid_request",

View File

@@ -0,0 +1,45 @@
class DurationParser
UNITS = {
"s" => 1, # seconds
"m" => 60, # minutes
"h" => 3600, # hours
"d" => 86400, # days
"w" => 604800, # weeks
"M" => 2592000, # months (30 days)
"y" => 31536000 # years (365 days)
}
# Parse a duration string into seconds
# Accepts formats: "1h", "30m", "1d", "1M" (month), "3600" (plain number)
# Returns integer seconds or nil if invalid
# Case-sensitive: 1s, 1m, 1h, 1d, 1w, 1M (month), 1y
def self.parse(input)
# Handle integers directly
return input if input.is_a?(Integer)
# Convert to string and strip whitespace
str = input.to_s.strip
# Return nil for blank input
return nil if str.blank?
# Try to parse as plain number (already in seconds)
if str.match?(/^\d+$/)
return str.to_i
end
# Try to parse with unit (e.g., "1h", "30m", "1M")
# Allow optional space between number and unit
# Case-sensitive to avoid confusion (1m = minute, 1M = month)
match = str.match(/^(\d+)\s*([smhdwMy])$/)
return nil unless match
number = match[1].to_i
unit = match[2]
multiplier = UNITS[unit]
return nil unless multiplier
number * multiplier
end
end

View File

@@ -271,7 +271,7 @@ class OidcClaimsSecurityTest < ActionDispatch::IntegrationTest
'{"id_token":{"email":{"essential":true}}}', '{"id_token":{"email":{"essential":true}}}',
'{"userinfo":{"groups":{"values":["admin"]}}}', '{"userinfo":{"groups":{"values":["admin"]}}}',
'{"id_token":{"custom_claim":"custom_value"}}', '{"id_token":{"custom_claim":"custom_value"}}',
'invalid-json' "invalid-json"
] ]
malicious_claims.each do |claims_value| malicious_claims.each do |claims_value|

View File

@@ -76,7 +76,7 @@ class OidcPromptLoginTest < ActionDispatch::IntegrationTest
# Should redirect to sign in because session is too old # Should redirect to sign in because session is too old
assert_response :redirect assert_response :redirect
assert_redirected_to /signin/ assert_redirected_to(/signin/)
# Sign in again # Sign in again
post "/signin", params: { post "/signin", params: {
@@ -194,7 +194,7 @@ class OidcPromptLoginTest < ActionDispatch::IntegrationTest
# Should redirect to sign in # Should redirect to sign in
assert_response :redirect assert_response :redirect
assert_redirected_to /signin/ assert_redirected_to(/signin/)
# Sign in again (simulating user re-authentication) # Sign in again (simulating user re-authentication)
post "/signin", params: { post "/signin", params: {