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
Fix capture and handle expired token #4956
Conversation
Codecov Report
@@ Coverage Diff @@
## master #4956 +/- ##
=========================================
- Coverage 6.02% 6.01% -0.01%
=========================================
Files 107 107
Lines 9850 9851 +1
=========================================
Hits 593 593
- Misses 9100 9101 +1
Partials 157 157
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
I am not able to see the full coverage report. |
b5ffc67
to
78eac4e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment! Thanks for the contribution! @MUzairS15
@@ -156,19 +208,27 @@ function PerformanceProfile({ updateProgress, enqueueSnackbar, closeSnackbar }) | |||
|
|||
function handleError(msg) { | |||
return function (error) { | |||
updateProgress({ showProgress : false }); | |||
if (error.source.errors[0].message != undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do a type check here? And additionally use optional chaining
[Grover] "Cookie Monster, come out and play." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MUzairS15, thanks for this PR!
This PR was discussed on today's Meshery meeting (we missed you ;) ). A couple comments were given such as "Can the cookie be used to determine session state / token expiry?", "How is this going to be applied to each UI / endpoint? It could be easy to miss an endpoint.", "Can this be achieved in NextJS with one central configuration?", "The golang middleware attached to each endpoint verifies token expiration and can redirect the user. This would be a central approach, too."
Current implementation redirects user to login but it fails.
In the UI itself? Yes, we can do this.I thought about this but later resolved to rely on the server as in
In data-fetch.js Pls correct me if I am wrong. |
@leecalcote Can you suggest, should I handle error or add check for whether token is still valid or not in |
Are you referring to the current implementation (on master branch)? |
Token validation can only be done on the server/cloud. Rather you can check for the cookie key (token) be present on all requests that includes credential(also called cookies). |
Yes, on master branch (server code, redirect fails, see screenshot above). And I have added logic to redirect from UI. |
When token expires, cookie is not cleared, so cookie (token) will be present. |
Yeah that's what you should do, intercept every request that passes cookie to server. Do it in data fetch itself.
That's a good thought, but token is set to session expire policy, i.e, it will not expire frequently and only in two conditions:
SO the case is extremely rare, meanwhile in case it is not correct (i.e., the auth token expired) the server will automatically redirect to the provider UI. @Utkarsh-pro do you remember the token expiry time? |
I tried with an expired token but was not redirected to provider UI. |
Okay let's have a check at two levels:
What do you say @MUzairS15 ? What are the things needed for the 2 to be done, if you have any idea. |
In server
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR @MUzairS15
So what you have done on the server is:
- check for token cookie being present
- If not present redirect to provider UI
- else marshal the cookie token and authenticate the user.
Just one concern, WHy you have added graphql in between? Is there any specific usecase?
I think this is not touching any graphql domain. Do we?
handlers/middlewares.go
Outdated
provider.Logout(w, req) | ||
} | ||
|
||
graphQlError := []Body{{"expired"}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, we are not touching graphQL, (just for sake of the name graphQlError
) I will change the name.
I am sending `{
"errors": {[
"error" : "expired"
]}
}
` as json to get it when we do a query when token becomes invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think giving more verbose error will help, like auth token expired
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
handlers/middlewares.go
Outdated
@@ -56,7 +65,26 @@ func (h *Handler) AuthMiddleware(next http.Handler) http.Handler { | |||
// } | |||
// return | |||
if provider.GetProviderType() == models.RemoteProviderType { | |||
provider.Logout(w, req) | |||
if err.Error() == "http: named cookie not present" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use contains function for this. https://pkg.go.dev/strings#Contains
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
handlers/middlewares.go
Outdated
func (h *Handler) validateAuth(provider models.Provider, req *http.Request) (bool, error) { | ||
err := provider.GetSession(req) | ||
if err == nil { | ||
// logrus.Debugf("session: %v", sess) | ||
return true | ||
return true, err | ||
} | ||
// logrus.Errorf("session invalid, error: %v", err) | ||
return false | ||
return false, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can delete the unusable comments like seen here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, will remove.
<GenericModal | ||
open={open} | ||
handleClose={handleClose} | ||
Content={ | ||
<Box sx = {style}> | ||
<Typography id="transition-modal-title" variant="h6" component="h2" className={classes.modal}> | ||
<span className = {classes.span}>ⓘ</span>Session Expired | ||
</Typography> | ||
{ counter && <Typography id="transition-modal-description" className = {classes.modalText} > | ||
Your session has expired. | ||
You will now be redirected to login... {counter} | ||
</Typography> | ||
} | ||
</Box> | ||
} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please extract this dialog and it's style in a separate component. They have been used twice on different pages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
); | ||
}, | ||
autoHideDuration : 8000, }); | ||
if (error.source.errors[0].message != undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (error.source.errors[0].message != undefined) { | |
if (error?.source?.errors?.[0]?.message) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
useEffect(() => { | ||
const timer = setTimeout(() => { | ||
setCounter(counter - 1) | ||
}, 1000) | ||
return () => clearTimeout(timer) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The useEffect Body runs on every state change which is not desired. Actually this modal can be placed in it's own functional component for the purpose of re-usability and then this implementation will look good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
handlers/middlewares.go
Outdated
@@ -56,7 +65,26 @@ func (h *Handler) AuthMiddleware(next http.Handler) http.Handler { | |||
// } | |||
// return | |||
if provider.GetProviderType() == models.RemoteProviderType { | |||
provider.Logout(w, req) | |||
if err.Error() == "http: named cookie not present" { | |||
provider.Logout(w, req) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is solved with the proposed changes, as we will not redirect from the server in case of an invalid session, instead query will fail, and UI will handle it by alerting the user.
bafa989
to
ab905ed
Compare
ui/components/ExpiredModal.js
Outdated
open={open} | ||
onClose={handleClose} | ||
> | ||
<Box sx={style}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<Box sx={style}> | |
<Box className={classes.box}> |
handlers/middlewares.go
Outdated
authError := []Body{{"auth-token expired"}} | ||
errors := Error{authError} | ||
jsonMsg, err := json.Marshal(errors) | ||
if err != nil { | ||
logrus.Errorf("Error marshaling response") | ||
http.Error(w, "unable to authenticate user", http.StatusInternalServerError) | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
authError := []Body{{"auth-token expired"}} | |
errors := Error{authError} | |
jsonMsg, err := json.Marshal(errors) | |
if err != nil { | |
logrus.Errorf("Error marshaling response") | |
http.Error(w, "unable to authenticate user", http.StatusInternalServerError) | |
return | |
} |
Signed-off-by: MUzairS15 <muzair.shaikh810@gmail.com>
910a1d9
to
1c864f5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After 30 mins long iteration, we got the root of the problem.
SO the /user/login
is redirecting to the meshery cloud for the user login, but since the redirection is from the server the cloud takes server on localhost:9081 as client and further failing because server can't act as a client and this is the reason behind the cors error.
Cross origin request from the server is denied on the cloud for the Login and that's how it should behave. You can't [instantiate] a login from the server.
Now since we are redirecting to the provider UI now, the actual instantiation of login can be done through react-client.
Cookie Policy:
- The cookie expiration policy is set to session, i.e., the cookie invalidates on the new session.
- It has its own expiry time more than 24 hours in case the session is not closed,
We are touching both the cases and all the cases the user can open meshery and cannot use any meshery service without being authenticated.
There can be a need of slight UX improvemnt in terms of the first load with invalid token sent to meshery and being validated, but that's a seperate concern and is out of the scope of this PR.
I think this PR can be merged, and you can see the changes with your eyes, the all functions being working the way they should.
UI improvements (minor flash between meshery homepage to going to provider login page (only once)) can be done seprately.
// @leecalcote |
@MUzairS15, it'd be great for you to quick a quick demo of this work on a Meshery Development Meeting. There's one today in 30 minutes, if you're free. Details here: https://meet.layer5.io |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
@sudo-NithishKarthik what do you think? #4956 (review) |
@sudo-NithishKarthik ping |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
@MUzairS15 will you put this on the agenda for next week's Meshery Dev meeting? |
Yes @leecalcote |
Discussed again today. The current server-side redirect is good and the return of the user-facing modal is also desirable. |
Signed-off-by: MUzairS15 <muzair.shaikh810@gmail.com>
Signed-off-by: MUzairS15 <muzair.shaikh810@gmail.com>
@@ -24,7 +23,6 @@ func (h *Handler) ProviderHandler(w http.ResponseWriter, r *http.Request) { | |||
http.SetCookie(w, &http.Cookie{ | |||
Name: h.config.ProviderCookieName, | |||
Value: p.Name(), | |||
Expires: time.Now().Add(h.config.ProviderCookieDuration), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes meshery-provider
cookie as Session cookie.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✔️
Signed-off-by: MUzairS15 <muzair.shaikh810@gmail.com>
Signed-off-by: MUzairS15 muzair.shaikh810@gmail.com
Description
This PR fixes #3935
Notes for Reviewers
This PR also addresses #3919
Signed commits
1.mov