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

Catch OIDC error #13078

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

dacook
Copy link
Member

@dacook dacook commented Jan 15, 2025

Catches the OAuth exception listed here: https://app.bugsnag.com/yaycode/openfoodnetwork-uk/errors/66e89c5fdf0c335670df0dd3?filters%5Bevent.since%5D=all (note that the Faraday::ServerError is already handled, although I haven't added a spec for it.)

What? Why?

What should we test?

It occurs when the session dies for some reason. I'm not sure if there's a way to trigger it.

Manually triggered within a spec:

image

Release notes

Changelog Category (reviewers may add a label for the release notes):

  • User facing changes
  • API changes (V0, V1, DFC or Webhook)
  • Technical changes only
  • Feature toggled

@dacook dacook requested a review from mkllnk January 15, 2025 06:05
@mkllnk
Copy link
Member

mkllnk commented Jan 16, 2025

It occurs when the session dies for some reason. I'm not sure if there's a way to trigger it.

I think that you invalidate tokens in Keycloak. So that's possible for manual testing but not automated testing. There we just have to mock the response.

Comment on lines 40 to 43
ActionController::ParameterMissing => e
ActionController::ParameterMissing,
Rack::OAuth2::Client::Error => e
flash[:error] = e.message
redirect_to admin_product_import_path
Copy link
Member

Choose a reason for hiding this comment

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

Does the flash message persist or disappear automatically?

Copy link
Member Author

Choose a reason for hiding this comment

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

In my testing I confirmed that error messages persist.
I remember this was intentional as part of the BUU update (other messages auto dismiss, but errors need to be dismissed by the user).

@dacook
Copy link
Member Author

dacook commented Jan 16, 2025

I think that you invalidate tokens in Keycloak.

Thanks, can you describe how I would do that? I just tried logging in to Les Communs with the testdfc@protonmail.com details in BitWarden, but it only showed my current browser session:
https://login.lescommuns.org/auth/realms/data-food-consortium/account/#/security/device-activity

Is that the right account?

Hmm, maybe it's because the session has ended already! I'll stage this PR and see what happens.

@dacook dacook added pr-staged-au staging.openfoodnetwork.org.au and removed pr-staged-au staging.openfoodnetwork.org.au labels Jan 16, 2025
@dacook
Copy link
Member Author

dacook commented Jan 16, 2025

Oh it's currently only connected on uk-staging. It shows the session is active, with no error: https://staging.openfoodnetwork.org.uk/admin/oidc_settings

So I can see the token is valid, but don't know how to invalidate it still.

@dacook
Copy link
Member Author

dacook commented Jan 16, 2025

Tried to test in spec/system/admin/dfc_product_import_spec.rb with:

   allow(DfcRequest).to receive(:call).and_raise(Rack::OAuth2::Client::Error, "session problem")

But no luck for some reason.

So I tried to manually replicate this in dev. With an invalid refresh_token, the import works as usual. I guess that's only needed for refreshing. With an invalid token, a 403 error message appears (existing functionality):

 OidcAccount.first.update! token: "blah"

Screenshot 2025-01-16 at 4 04 19 pm

So I don't know how to reliably replicate this issue. @mkllnk do you think it would be ok to merge it as-is and see how we go? Or wait until it occurs on the staging environment, stage it, and confirm it then?

@mkllnk
Copy link
Member

mkllnk commented Jan 16, 2025

allow(DfcRequest).to receive(:call).and_raise(Rack::OAuth2::Client::Error, "session problem")

It's not a class method, it's an instance method. You'll need allow_any_instance_of.

@dacook
Copy link
Member Author

dacook commented Jan 16, 2025

It's not a class method, it's an instance method. You'll need allow_any_instance_of.

Oops, thanks you're absolutely right. I did try that before, but now I see that I was testing it wrong that time. Will try again next week.

I'm not sure if this can be tested easily, or needs to be.
@dacook dacook force-pushed the catch-oidc-error-12987 branch from aee70df to 4ce2730 Compare January 21, 2025 00:58
@dacook dacook marked this pull request as ready for review January 21, 2025 01:10
@dacook dacook requested a review from mkllnk January 21, 2025 01:10
Copy link
Member

@mkllnk mkllnk left a comment

Choose a reason for hiding this comment

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

Nice catch! But I think that we can improve this if you have time.

spec/system/admin/dfc_product_import_spec.rb Show resolved Hide resolved
I forgot how hard it is to do view stuff in controllers.
I tried using the short lazy-lookup key '.oauth_error_html', which is supposed to work in controllers. But perhaps it doesn't work within a rescue?
@dacook dacook requested a review from mkllnk January 21, 2025 05:20
Copy link
Member

@mkllnk mkllnk left a comment

Choose a reason for hiding this comment

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

Nice to have the link. What about updating the OIDC account and delete the token so that it can be refreshed more easily?

app/controllers/admin/dfc_product_imports_controller.rb Outdated Show resolved Hide resolved
@dacook
Copy link
Member Author

dacook commented Jan 21, 2025

What about updating the OIDC account and delete the token so that it can be refreshed more easily?

Ah, I misunderstood your initial message and didn't read that as a suggested change 😅

@dacook
Copy link
Member Author

dacook commented Jan 22, 2025

What about updating the OIDC account and delete the token so that it can be refreshed more easily?

@mkllnk I made a start on this, but have to admit I'm not really sure and it might not be worth following up. Am I on the right track, or should we just stop here (at "[fixup] Sanitise content from external source") and move on?

app/controllers/admin/dfc_product_imports_controller.rb Outdated Show resolved Hide resolved
Comment on lines 84 to 89
rescue Rack::OAuth2::Client::Error => e
@user.oidc_account.update!(
token: nil,
refresh_token: nil
)
throw e
Copy link
Member

Choose a reason for hiding this comment

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

Yes, that's what I imagined. I also imagined a custom error class but that's just nice to have.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, that crossed my mind too but I figured it could be added later if needed.

engines/dfc_provider/app/services/dfc_request.rb Outdated Show resolved Hide resolved
dacook and others added 2 commits January 22, 2025 14:05
Co-authored-by: Maikel <maikel@email.org.au>
@dacook dacook force-pushed the catch-oidc-error-12987 branch from 5bc0335 to 4e15a6e Compare January 22, 2025 03:49
But the test session isn't active!

[skip ci]
@dacook dacook force-pushed the catch-oidc-error-12987 branch from 4e15a6e to ec85822 Compare January 22, 2025 04:00
Comment on lines 84 to 89
rescue Rack::OAuth2::Client::Error => e
@user.oidc_account.update!(
token: nil,
refresh_token: nil
)
throw e
Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, that crossed my mind too but I figured it could be added later if needed.

@@ -88,5 +88,33 @@
products = graph.select { |s| s.semanticType == "dfc-b:SuppliedProduct" }
expect(products).to be_present
end

Copy link
Member Author

Choose a reason for hiding this comment

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

@mkllnk I've had a go at speccing this, but in order to test that it clears the tokens, we need to set tokens first.

I've copied secret vars from Bitwarden and am able to make these requests, but the test session isn't active and results in the error "invalid_grant :: Session not active" (the exact error I'm trying to test!)

Am I doing things the long way round? Let me know if you see a better way.

Otherwise, can you please help me to refresh the session? Then hopefully the below spec will work..

Copy link
Member

Choose a reason for hiding this comment

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

I wouldn't use VCR for this because the spec then depends on the state of your session. The one in Bitwarden is probably outdated. Use webmock. And you got the right error response to fill your example already.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the feedback. I had another go, but I can't seem to set up the right context for this case to work.

Maybe it's not worth trying to make the spec. What if we merge this without a spec, and see if it solves the errors?

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

Successfully merging this pull request may close these issues.

[DFC Orders] Improve OIDC Error Handling
2 participants