Skip to content

Conversation

@npalaska
Copy link
Member

On the Pbench Dashboard when the OIDC authentication redirect request is successful, the OIDC broker will redirect the user back to the Pbench auth page with a location header containing session_id and code. We have to use this code to make a POST request against the OIDC token endpoint. If the token endpoint request is successful we log the user in and redirect the user to the overview page.

The POST request might look like the following:


http://<auth-server>/realms/pbench/protocol/openid-connect/token

grant_type=authorization_code
code=<code>
client_id=pbench-client
redirect_uri=http://<pbench-dashboard>/login

Note: This also makes a request to the OIDC userinfo endpoint to fetch and then store the user info as a state value.

This PR is currently rebased on commits from PR #3233

PBENCH-1073

@npalaska npalaska requested a review from MVarshini February 12, 2023 09:40
@npalaska npalaska self-assigned this Feb 12, 2023
@npalaska npalaska added Dashboard Of and relating to the Dashboard GUI Users Of and relating to working with users. labels Feb 12, 2023
@npalaska npalaska added this to the v0.72 milestone Feb 12, 2023
Copy link
Member

@webbnh webbnh left a comment

Choose a reason for hiding this comment

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

Here are a few things to consider.

Copy link
Member

@dbutenhof dbutenhof left a comment

Choose a reason for hiding this comment

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

Also ... you should look in src/utils/axiosInstance.js. We have an API interceptor that adds the bearer token and reports authentication failures. That code ought to be handling expiration by attempting to use the refresh token to negotiate a new access token; otherwise our joy in using the new dashboard code will be shortlived. 😆

(And I appear to have a mind comment pending that I "abandoned" days ago without submitting. Nice of GitHub to remember it, I guess...)

@portante portante modified the milestones: v0.72, v0.73 Mar 14, 2023
@npalaska npalaska force-pushed the pbench_1073 branch 2 times, most recently from 94d4730 to 7a62855 Compare March 21, 2023 21:28
@npalaska npalaska marked this pull request as ready for review March 21, 2023 21:29
@npalaska
Copy link
Member Author

Okay, opened for review now and I have tried to address most of the relevant comments, but many here may no longer be relevant.

- New dependency added @react-keycloak/web and keycloak-js
- Checks the SSO session by wrapping the entire App inside
  KeycloakProvider.
- Removed the current use of login and registration related
  components.

PBENCH-1073
Copy link
Member

@webbnh webbnh left a comment

Choose a reason for hiding this comment

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

There is a bunch more code to be ripped out. 🙂

Copy link
Member

@dbutenhof dbutenhof left a comment

Choose a reason for hiding this comment

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

Coming along nicely. As many of Webb's comments suggest, a Prettier run would be good. We should probably add the prettier hook into our eslint config to check formatting in the CI as we do for Python, which would eliminate most concerns of that nature during reviews.

Copy link
Member

@dbutenhof dbutenhof left a comment

Choose a reason for hiding this comment

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

Yeah, I almost kinda wish the prettierization had been a separate PR. It was a bit awkward to re-review this morning because, while the reformatting was segregated in a separate commit (thanks), there were new code changes on top of that commit. Ah, well; water over and/or under the bridge ...

Anyway, I think we're converging here. I'm still not sure I understand the flows around page reload and the interactions with cookies vs redux store as related to the OIDC session management, and a bit more clarity would help. Beyond that I think we're into streamlining and cleanup...

Copy link
Member

@webbnh webbnh left a comment

Choose a reason for hiding this comment

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

There is still a bunch more dead code to be removed, and I think you should take a close look at all the (new) places where you are using ?. (I pointed out a bunch of suspicious ones). And, there are a few other nits and small things.

Copy link
Member

@webbnh webbnh left a comment

Choose a reason for hiding this comment

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

BTW, thanks for putting the Prettier changes in their own commit! FWIW, when Dave and I suggested running Prettier, I think we were thinking that it would affect only your changes or only your changed modules. (We weren't really aware that so much of the overall code was not up to spec....)

Below is an additional question I had. Also, there are a few lingering items from my previous review-passes:

Comment on lines 40 to 41
if (keycloak.authenticated) {
Cookies.set("isLoggedIn", true, {
Copy link
Member

@webbnh webbnh Mar 23, 2023

Choose a reason for hiding this comment

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

This if statement has no else block...which is odd....

What happens if the user fails his/her authentication? Are they "stuck" on the OIDC login page and never come back to the Dashboard? Or, does OIDC somehow send them back with failure status?

That is, when execution reaches line 40 here, can authenticated ever be anything but true? If so, shouldn't we have an else branch which acknowledges that the login failed (i.e, in opposition to line 44)? And, if not, do we really need/want to be testing it?

Copy link
Member Author

@npalaska npalaska Mar 23, 2023

Choose a reason for hiding this comment

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

What happens if the user fails his/her authentication? Are they "stuck" on the OIDC login page and never come back to the Dashboard? Or, does OIDC somehow send them back with failure status?

Yeah, the Keycloak will not redirect them back to the dashboard in case of authentication failure, they will be given a chance to re-enter their credentials. Users are not necessarily stuck there they can hit the back button of the browser to come back to the dashboard landing page and have a view of the non-logged-in user.

That is, when execution reaches line 40 here, can authenticated ever be anything but true? If so, shouldn't we have an else branch which acknowledges that the login failed (i.e, in opposition to line 44)? And, if not, do we really need/want to be testing it?

We could display toastAction like else {dispatch(showToast("danger", "Not authenticated!"));} but I don't think that's necessary. Landing on auth page without logging in, users already know that they are not logged in and we don't need to explicitly tell them that.

Copy link
Member

Choose a reason for hiding this comment

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

I guess I'm confused about the sequencing.

When the Dashboard is initially loaded, we arrive at the code here before the user does the Keycloak dance, but after we've initialized the Keycloak plug-in and created the keycloak object. So, on the first pass through here, keycloak.authenticated will be false, and that's OK, and we'll go on to render some sort of helpful default page. On subsequent page renderings (e.g., when the Keycloak login redirects back to the Dashboard), we'll come through here and keycloak.authenticated will be true, and so we'll set our cookie-thing here and raise a toast to the user's success.

So, to answer my own questions: yes, we do want to test keycloak.authenticated here (because initially, at least, it will be false); no, we don't need an else clause on this if (because that execution path is "normal" and unremarkable); and, as you said, when an authentication attempt fails, we won't end up here.

But, execution will come through here at other times, right? We don't necessarily want to toast the user every time, do we? (We may or may not want to update the cookie...I'm less clear on that...but, then, I'm not sure that we need/want this cookie at all....)

So, I'm still wondering about this if statement: perhaps it should be moved to somewhere where we know the answer and don't have to test for it.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure that we need/want this cookie at all....

isLoggedIn cookie has an expiry of refreshToken so it lives across the multiple App rendering. I could check the value of keycloak.authenticated inside the protected route of the App but on each rendering, the keycloak object gets reinitialized and so the value is not there yet. The problem is if I don't use this cookie in the protected route and instead rely on keycloak.authenticated value when the App renders it's gonna immediately display the DANGER toast and redirect the auth page.

I also think ideally we shouldn't need to maintain cookies internally related to the authentication but I couldn't find a way around it at this time. This is something I need to spend some more time understanding the keycloak-js plugin and fix this reload problem.

So, I'm still wondering about this if statement: perhaps it should be moved to somewhere where we know the answer and don't have to test for it.

What do you mean? We know the answer to what happens on the if statement and what will happen outside the if statement, right?

Copy link
Member

@webbnh webbnh Mar 27, 2023

Choose a reason for hiding this comment

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

What do you mean?

We need the if statement here (we think...) because, at this point in the code, we don't know whether keycloak.authenticated is true or false. The question is, is there some point, up- or down-stream from here, where we already know the answer? If so, perhaps we can move the if statement there, so that we don't have to ask the question here (or there!).

@npalaska npalaska requested a review from dbutenhof March 24, 2023 15:07
dbutenhof
dbutenhof previously approved these changes Mar 24, 2023
dbutenhof
dbutenhof previously approved these changes Mar 24, 2023
@dbutenhof
Copy link
Member

Wow: that's a really weird unit test failure, considering you haven't changed any server code. Hard to imagine re-submitting will make any difference, but I'm trying anyway.

@npalaska
Copy link
Member Author

Wow: that's a really weird unit test failure, considering you haven't changed any server code. Hard to imagine re-submitting will make any difference, but I'm trying anyway.

I guess re-submitting worked mysteriously 🤔

@webbnh
Copy link
Member

webbnh commented Mar 24, 2023

that's a really weird unit test failure, considering you haven't changed any server code

I'm guessing that it's a missing fixture (or a fixture scope change, or a change to a "chain" of fixture inclusions) in the test code, and that it has little or nothing to do with Server code.

@webbnh
Copy link
Member

webbnh commented Mar 24, 2023

I guess re-submitting worked mysteriously

Apparently so. 😬

Copy link
Member

@webbnh webbnh left a comment

Choose a reason for hiding this comment

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

These latest changes look good; we just need to conclude the discussions from the previous reviews.

Copy link
Member

@webbnh webbnh left a comment

Choose a reason for hiding this comment

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

Looking good. I think you should add some more to the getDatasets error handler. Beyond that, I found what I think are a couple of unneeded async's, a handful of unneeded ?.'s, and some other small things which you should consider addressing.

And, there are a few lingering issues from my earlier passes:

But, I think we're getting close.

Comment on lines -199 to +103
) : (
<></>
)}
{<></>}
Copy link
Member

Choose a reason for hiding this comment

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

This looks like an orphan which should have been removed. (I.e., I think this was a placeholder for the second half of a ternary; you removed the first half, so now we don't need the "no-op" second half.)

@npalaska npalaska requested review from dbutenhof and webbnh March 25, 2023 05:53
Copy link
Contributor

@MVarshini MVarshini left a comment

Choose a reason for hiding this comment

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

The less files formatting has been changed.

Also, imports in few files are changed from " " to ' '

@npalaska
Copy link
Member Author

Also, imports in few files are changed from " " to ' '

I just re-checked, prettier took care of it and it seems like all the imports in all the files now have " "

The less files formatting has been changed.

Are we not supposed to change less files. prettier actually re-formatted them.

Copy link
Member

@webbnh webbnh left a comment

Choose a reason for hiding this comment

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

This looks good enough for now.

I think there is an orphan bit of code which should have been removed, but it's the HTML/Javascript equivalent of a no-op, so it's not worth haggling over.

And, I'm still unsettled by the if statement in authCookies(), but we can work on "flow" later.

Copy link
Member

@dbutenhof dbutenhof left a comment

Choose a reason for hiding this comment

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

I'm not thrilled about the error formatting, but this is a problem throughout the dashboard we probably need to address separately.

dispatch(showToast(DANGER, error?.response?.data?.message));
const msg = error.response?.data?.message;
dispatch(
showToast(DANGER, msg ? msg : `Error response: ${error.response}`)
Copy link
Member

Choose a reason for hiding this comment

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

How will Javascript format a Response object? Is that really what we want to appear in the toast? If the response body is a JSON and has message we want to show it; it could also be JSON without a message, or a non-JSON response payload, or there could be no payload at all. I'm not sure how "clever" we want to be here, but probably the final fallback would be the HTTP status code and the code's generic message (response.reason, I think, in Python, though I'm not sure offhand how the Javascript response object differs.) So, maybe, just error.response.data.message or the HTTP status and reason? (But what if we get an error exception that doesn't even have a Response object? In this code we're back to a stringified undefined.)

Copy link
Member

Choose a reason for hiding this comment

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

How will Javascript format a Response object?

It's a valid question which I decided to punt on the principal of the perfect being the enemy of the done. This is something that we can iterate on.

Is that really what we want to appear in the toast?

Probably, not; but my instinct was that it was better than a generic (local fixed-text) message.

I'm not sure how "clever" we want to be here

Only as clever as we need to be and no cleverer. If you're reasonably sure that there will be a response.reason, I'm OK with using that instead of the whole response (I was hoping that Javascript would do something reasonable, and that having the whole response might be be illuminating). If we use the chaining dereference, I'm OK with seeing an undefined in the rare case that we get an error with no other information (i.e., that's not much different from getting a literal "something went wrong" message....)

@npalaska npalaska merged commit 480dcdd into distributed-system-analysis:openid-connect Mar 27, 2023
npalaska added a commit to npalaska/pbench that referenced this pull request Mar 27, 2023
…distributed-system-analysis#3250)

* Dashboard integration with keycloak

- New dependency added @react-keycloak/web and keycloak-js
- Checks the SSO session by wrapping the entire App inside
  KeycloakProvider.
- Removed the current use of login and registration related
  components.
- Removed all the changes and files that got void after this
  authentication change.
- Also ran prettier on the entire src directory.

PBENCH-1073
npalaska added a commit to npalaska/pbench that referenced this pull request Mar 28, 2023
…distributed-system-analysis#3250)

* Dashboard integration with keycloak

- New dependency added @react-keycloak/web and keycloak-js
- Checks the SSO session by wrapping the entire App inside
  KeycloakProvider.
- Removed the current use of login and registration related
  components.
- Removed all the changes and files that got void after this
  authentication change.
- Also ran prettier on the entire src directory.

PBENCH-1073
npalaska added a commit to npalaska/pbench that referenced this pull request Mar 30, 2023
…distributed-system-analysis#3250)

* Dashboard integration with keycloak

- New dependency added @react-keycloak/web and keycloak-js
- Checks the SSO session by wrapping the entire App inside
  KeycloakProvider.
- Removed the current use of login and registration related
  components.
- Removed all the changes and files that got void after this
  authentication change.
- Also ran prettier on the entire src directory.

PBENCH-1073
npalaska added a commit to npalaska/pbench that referenced this pull request Mar 31, 2023
…distributed-system-analysis#3250)

* Dashboard integration with keycloak

- New dependency added @react-keycloak/web and keycloak-js
- Checks the SSO session by wrapping the entire App inside
  KeycloakProvider.
- Removed the current use of login and registration related
  components.
- Removed all the changes and files that got void after this
  authentication change.
- Also ran prettier on the entire src directory.

PBENCH-1073
@npalaska npalaska mentioned this pull request Mar 31, 2023
npalaska added a commit that referenced this pull request Mar 31, 2023
…#3250)

* Dashboard integration with keycloak

- New dependency added @react-keycloak/web and keycloak-js
- Checks the SSO session by wrapping the entire App inside
  KeycloakProvider.
- Removed the current use of login and registration related
  components.
- Removed all the changes and files that got void after this
  authentication change.
- Also ran prettier on the entire src directory.

PBENCH-1073
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Of and relating to the Dashboard GUI Users Of and relating to working with users.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants