diff --git a/server/auth/types/authentication_type.test.ts b/server/auth/types/authentication_type.test.ts index d3f6026bb..03825216a 100644 --- a/server/auth/types/authentication_type.test.ts +++ b/server/auth/types/authentication_type.test.ts @@ -27,6 +27,9 @@ class DummyAuthType extends AuthenticationType { isValidCookie() { return Promise.resolve(true); } + refreshAccessToken() { + return Promise.resolve(''); + } requestIncludesAuthInfo() { return false; } diff --git a/server/auth/types/authentication_type.ts b/server/auth/types/authentication_type.ts index 56ec21463..e56a337f6 100755 --- a/server/auth/types/authentication_type.ts +++ b/server/auth/types/authentication_type.ts @@ -138,6 +138,11 @@ export abstract class AuthenticationType implements IAuthenticationType { cookie = undefined; } + let newAuthHeaderValue = ''; + if (cookie) { + newAuthHeaderValue = await this.refreshAccessToken(cookie, request); + } + if (!cookie || !(await this.isValidCookie(cookie, request))) { // clear cookie this.sessionStorageFactory.asScoped(request).clear(); @@ -160,10 +165,14 @@ export abstract class AuthenticationType implements IAuthenticationType { } // cookie is valid // build auth header - const authHeadersFromCookie = this.buildAuthHeaderFromCookie(cookie!, request); - Object.assign(authHeaders, authHeadersFromCookie); - const additonalAuthHeader = await this.getAdditionalAuthHeader(request); - Object.assign(authHeaders, additonalAuthHeader); + if (!!newAuthHeaderValue) { + Object.assign(authHeaders, { authorization: newAuthHeaderValue }); + } else { + const authHeadersFromCookie = this.buildAuthHeaderFromCookie(cookie!, request); + Object.assign(authHeaders, authHeadersFromCookie); + const additonalAuthHeader = await this.getAdditionalAuthHeader(request); + Object.assign(authHeaders, additonalAuthHeader); + } } // resolve tenant if necessary @@ -277,6 +286,10 @@ export abstract class AuthenticationType implements IAuthenticationType { cookie: SecuritySessionCookie, request: OpenSearchDashboardsRequest ): Promise; + public abstract refreshAccessToken( + cookie: SecuritySessionCookie, + request: OpenSearchDashboardsRequest + ): Promise; protected abstract handleUnauthedRequest( request: OpenSearchDashboardsRequest, response: LifecycleResponseFactory, diff --git a/server/auth/types/basic/basic_auth.ts b/server/auth/types/basic/basic_auth.ts index af7a8727f..118a5ed76 100644 --- a/server/auth/types/basic/basic_auth.ts +++ b/server/auth/types/basic/basic_auth.ts @@ -101,6 +101,13 @@ export class BasicAuthentication extends AuthenticationType { ); } + async refreshAccessToken( + cookie: SecuritySessionCookie, + request: OpenSearchDashboardsRequest + ): Promise { + return ''; + } + handleUnauthedRequest( request: OpenSearchDashboardsRequest, response: LifecycleResponseFactory, diff --git a/server/auth/types/jwt/jwt_auth.ts b/server/auth/types/jwt/jwt_auth.ts index 3b8ef365a..5b37befa8 100644 --- a/server/auth/types/jwt/jwt_auth.ts +++ b/server/auth/types/jwt/jwt_auth.ts @@ -119,6 +119,13 @@ export class JwtAuthentication extends AuthenticationType { ); } + async refreshAccessToken( + cookie: SecuritySessionCookie, + request: OpenSearchDashboardsRequest + ): Promise { + return ''; + } + handleUnauthedRequest( request: OpenSearchDashboardsRequest, response: LifecycleResponseFactory, diff --git a/server/auth/types/multiple/multi_auth.ts b/server/auth/types/multiple/multi_auth.ts index 8763eaa4f..3b205a337 100644 --- a/server/auth/types/multiple/multi_auth.ts +++ b/server/auth/types/multiple/multi_auth.ts @@ -142,6 +142,18 @@ export class MultipleAuthentication extends AuthenticationType { } } + async refreshAccessToken( + cookie: SecuritySessionCookie, + request: OpenSearchDashboardsRequest + ): Promise { + const reqAuthType = cookie?.authType?.toLowerCase(); + if (reqAuthType && this.authHandlers.has(reqAuthType)) { + return this.authHandlers.get(reqAuthType)!.refreshAccessToken(cookie, request); + } else { + return ''; + } + } + handleUnauthedRequest( request: OpenSearchDashboardsRequest, response: LifecycleResponseFactory, diff --git a/server/auth/types/openid/openid_auth.ts b/server/auth/types/openid/openid_auth.ts index accabb7c1..7b3238efd 100644 --- a/server/auth/types/openid/openid_auth.ts +++ b/server/auth/types/openid/openid_auth.ts @@ -219,6 +219,27 @@ export class OpenIdAuthentication extends AuthenticationType { return true; } + return false; + } + + async refreshAccessToken( + cookie: SecuritySessionCookie, + request: OpenSearchDashboardsRequest + ): Promise { + if ( + cookie.authType !== this.type || + !cookie.username || + !cookie.expiryTime || + (!cookie.credentials?.authHeaderValue && !this.getExtraAuthStorageValue(request, cookie)) || + !cookie.credentials?.expires_at + ) { + return ''; + } + + if (cookie.credentials?.expires_at > Date.now()) { + return ''; + } + // need to renew id token if (cookie.credentials.refresh_token) { try { @@ -248,17 +269,17 @@ export class OpenIdAuthentication extends AuthenticationType { this.getExtraAuthStorageOptions() ); - return true; + return `Bearer ${refreshTokenResponse.idToken}`; } else { - return false; + return ''; } } catch (error: any) { this.logger.error(error); - return false; + return ''; } } else { // no refresh token, and current token is expired - return false; + return ''; } } diff --git a/server/auth/types/proxy/proxy_auth.ts b/server/auth/types/proxy/proxy_auth.ts index 346553a50..aeeb5ddc1 100644 --- a/server/auth/types/proxy/proxy_auth.ts +++ b/server/auth/types/proxy/proxy_auth.ts @@ -120,6 +120,13 @@ export class ProxyAuthentication extends AuthenticationType { ); } + async refreshAccessToken( + cookie: SecuritySessionCookie, + request: OpenSearchDashboardsRequest + ): Promise { + return ''; + } + handleUnauthedRequest( request: OpenSearchDashboardsRequest, response: LifecycleResponseFactory, diff --git a/server/auth/types/saml/saml_auth.ts b/server/auth/types/saml/saml_auth.ts index 5c5c3e426..8bf12d71a 100644 --- a/server/auth/types/saml/saml_auth.ts +++ b/server/auth/types/saml/saml_auth.ts @@ -161,6 +161,13 @@ export class SamlAuthentication extends AuthenticationType { ); } + async refreshAccessToken( + cookie: SecuritySessionCookie, + request: OpenSearchDashboardsRequest + ): Promise { + return ''; + } + handleUnauthedRequest( request: OpenSearchDashboardsRequest, response: LifecycleResponseFactory,