diff --git a/components/app-core/backend/auth.go b/components/app-core/backend/auth.go index 48dc86ad0d..cd6c5d8eda 100644 --- a/components/app-core/backend/auth.go +++ b/components/app-core/backend/auth.go @@ -42,6 +42,9 @@ const CFAdminIdentifier = "cloud_controller.admin" // SessionExpiresOnHeader Custom header for communicating the session expiry time to clients const SessionExpiresOnHeader = "X-Cap-Session-Expires-On" +// SessionExpiresAfterHeader Custom header for communicating the session expiry time to clients +const ClientRequestDateHeader = "X-Cap-Request-Date" + // EmptyCookieMatcher - Used to detect and remove empty Cookies sent by certain browsers var EmptyCookieMatcher *regexp.Regexp = regexp.MustCompile(portalSessionName + "=(?:;[ ]*|$)") @@ -95,15 +98,10 @@ func (p *portalProxy) loginToUAA(c echo.Context) error { return err } - // Explicitly tell the client when this session will expire. This is needed because browsers actively hide - // the Set-Cookie header and session cookie expires_on from client side javascript - expOn, err := p.GetSessionValue(c, "expires_on") + err = p.handleSessionExpiryHeader(c) if err != nil { - msg := "Could not get session expiry" - log.Error(msg+" - ", err) - return echo.NewHTTPError(http.StatusInternalServerError, msg) + return err } - c.Response().Header().Set(SessionExpiresOnHeader, strconv.FormatInt(expOn.(time.Time).Unix(), 10)) _, err = p.saveUAAToken(*u, uaaRes.AccessToken, uaaRes.RefreshToken) if err != nil { @@ -524,15 +522,10 @@ func (p *portalProxy) verifySession(c echo.Context) error { } } - // Explicitly tell the client when this session will expire. This is needed because browsers actively hide - // the Set-Cookie header and session cookie expires_on from client side javascript - expOn, err := p.GetSessionValue(c, "expires_on") + err = p.handleSessionExpiryHeader(c) if err != nil { - msg := "Could not get session expiry" - log.Error(msg+" - ", err) - return echo.NewHTTPError(http.StatusInternalServerError, msg) + return err } - c.Response().Header().Set(SessionExpiresOnHeader, strconv.FormatInt(expOn.(time.Time).Unix(), 10)) info, err := p.getInfo(c) if err != nil { @@ -547,6 +540,34 @@ func (p *portalProxy) verifySession(c echo.Context) error { return nil } +func (p *portalProxy) handleSessionExpiryHeader(c echo.Context) error { + + // Explicitly tell the client when this session will expire. This is needed because browsers actively hide + // the Set-Cookie header and session cookie expires_on from client side javascript + expOn, err := p.GetSessionValue(c, "expires_on") + if err != nil { + msg := "Could not get session expiry" + log.Error(msg+" - ", err) + return echo.NewHTTPError(http.StatusInternalServerError, msg) + } + c.Response().Header().Set(SessionExpiresOnHeader, strconv.FormatInt(expOn.(time.Time).Unix(), 10)) + + expiry := expOn.(time.Time) + expiryDuration := expiry.Sub(time.Now()) + + // Subtract time now to get the duration add this to the time provided by the client + if c.Request().Header().Contains(ClientRequestDateHeader) { + clientDate := c.Request().Header().Get(ClientRequestDateHeader) + clientDateInt, err := strconv.ParseInt(clientDate, 10, 64) + if err == nil { + clientDateInt += int64(expiryDuration.Seconds()) + c.Response().Header().Set(SessionExpiresOnHeader, strconv.FormatInt(clientDateInt, 10)) + } + } + + return nil +} + func (p *portalProxy) getUAAUser(userGUID string) (*interfaces.ConnectedUser, error) { log.Debug("getUAAUser") diff --git a/components/app-core/frontend/src/api/account.api.js b/components/app-core/frontend/src/api/account.api.js index 6deeba7a42..1176257786 100644 --- a/components/app-core/frontend/src/api/account.api.js +++ b/components/app-core/frontend/src/api/account.api.js @@ -46,7 +46,8 @@ function login(username, password) { var config = { headers: { - 'Content-Type': 'application/x-www-form-urlencoded' + 'Content-Type': 'application/x-www-form-urlencoded', + 'x-cap-request-date': moment().unix() } }; var data = $httpParamSerializer({ username: username, password: password }); @@ -72,7 +73,12 @@ * @public */ function verifySession() { - return $http.get('/pp/v1/auth/session/verify'); + var config = { + headers: { + 'x-cap-request-date': moment().unix() + } + }; + return $http.get('/pp/v1/auth/session/verify', config); } function userInfo() {