Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guard against OIDC Provider configuration being stale #5296

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

segiddins
Copy link
Member

Fixes TOB-RGM-14

Copy link

codecov bot commented Dec 1, 2024

Codecov Report

Attention: Patch coverage is 97.61905% with 1 line in your changes missing coverage. Please review.

Project coverage is 97.15%. Comparing base (642d6b5) to head (0509625).

Files with missing lines Patch % Lines
app/controllers/concerns/jwt_validation.rb 96.15% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master    #5296   +/-   ##
=======================================
  Coverage   97.14%   97.15%           
=======================================
  Files         457      458    +1     
  Lines        9564     9581   +17     
=======================================
+ Hits         9291     9308   +17     
  Misses        273      273           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@segiddins segiddins marked this pull request as ready for review December 1, 2024 22:36
Copy link
Member

@martinemde martinemde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly just style nitpicks. I like the module approach. Much cleaner.


def verify_jwt_time
now = Time.now.to_i
return if @jwt["nbf"] <= now && now < @jwt["exp"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤷‍♂️

Suggested change
return if @jwt["nbf"] <= now && now < @jwt["exp"]
return if (@jwt["nbf"]...@jwt["exp"]).include?(now)

It creates a range so maybe slightly less efficient, your call.

Comment on lines +41 to +42
# TODO: delete &. after all providers have updated their configuration
return unless @provider.configuration_updated_at&.before?(1.day.ago)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something about this is very hard to reason about for me. I think it almost reads like a double negative.

Suggested change
# TODO: delete &. after all providers have updated their configuration
return unless @provider.configuration_updated_at&.before?(1.day.ago)
return if @provider.configuration_updated_at.nil? # TODO: remove this line after all providers have updated their configuration
return if @provider.configuration_updated_at.after?(1.day.ago)

@@ -0,0 +1,5 @@
class AddConfigurationUpdatedAtToOIDCProviders < ActiveRecord::Migration[7.1]
def change
add_column :oidc_providers, :configuration_updated_at, :timestamp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you set a default here of epoch just so we don't have to guard for nil? I'm wondering if new providers will ever be updated immediately anyway or will there be a time gap while they crash the check above?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they'll all be updated within 30 minutes

raise UnsupportedIssuer, "Provider is missing jwks" if @provider.jwks.blank?
# TODO: delete &. after all providers have updated their configuration
return unless @provider.configuration_updated_at&.before?(1.day.ago)
raise UnsupportedIssuer, "Configuration last updated too long ago: #{@provider.configuration_updated_at}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this error happens there's nothing the user can do about it, no?

Should we indicate this with a 503, in effect saying "it's not you it's me".

Comment on lines +31 to +36
%w[nbf iat exp].each do |claim|
raise InvalidJWT, "Missing/invalid #{claim}" unless @jwt[claim].is_a?(Integer)
end
%w[iss jti].each do |claim|
raise InvalidJWT, "Missing/invalid #{claim}" unless @jwt[claim].is_a?(String)
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: could extract to constant {iss: String, ...} which would allocate once and be a little simpler.

end

def decode_jwt
@jwt = JSON::JWT.decode_compact_serialized(params.permit(:jwt).require(:jwt), jwt_key_or_secret)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is :skip_verification handled by the JWT lib?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging this pull request may close these issues.

2 participants