@@ -29,6 +29,7 @@ import {
29
29
import HTTP from 'http' ;
30
30
import HTTPS from 'https' ;
31
31
import { PeerCertificate } from 'tls' ;
32
+ import { Server , ServerStateCookieOptions } from '@hapi/hapi' ;
32
33
import { SecurityPluginConfigType } from '../../..' ;
33
34
import { SecuritySessionCookie } from '../../../session/security_cookie' ;
34
35
import { OpenIdAuthRoutes } from './routes' ;
@@ -37,6 +38,11 @@ import { callTokenEndpoint } from './helper';
37
38
import { composeNextUrlQueryParam } from '../../../utils/next_url' ;
38
39
import { getExpirationDate } from './helper' ;
39
40
import { AuthType , OPENID_AUTH_LOGIN } from '../../../../common' ;
41
+ import {
42
+ ExtraAuthStorageOptions ,
43
+ getExtraAuthStorageValue ,
44
+ setExtraAuthStorage ,
45
+ } from '../../../session/cookie_splitter' ;
40
46
41
47
export interface OpenIdAuthConfig {
42
48
authorizationEndpoint ?: string ;
@@ -93,6 +99,8 @@ export class OpenIdAuthentication extends AuthenticationType {
93
99
this . openIdAuthConfig . tokenEndpoint = payload . token_endpoint ;
94
100
this . openIdAuthConfig . endSessionEndpoint = payload . end_session_endpoint || undefined ;
95
101
102
+ this . createExtraStorage ( ) ;
103
+
96
104
const routes = new OpenIdAuthRoutes (
97
105
this . router ,
98
106
this . config ,
@@ -102,6 +110,7 @@ export class OpenIdAuthentication extends AuthenticationType {
102
110
this . coreSetup ,
103
111
this . wreckClient
104
112
) ;
113
+
105
114
routes . setupRoutes ( ) ;
106
115
} catch ( error : any ) {
107
116
this . logger . error ( error ) ; // TODO: log more info
@@ -135,6 +144,37 @@ export class OpenIdAuthentication extends AuthenticationType {
135
144
}
136
145
}
137
146
147
+ createExtraStorage ( ) {
148
+ // @ts -ignore
149
+ const hapiServer : Server = this . sessionStorageFactory . asScoped ( { } ) . server ;
150
+
151
+ const extraCookiePrefix = this . config . openid ! . extra_storage . cookie_prefix ;
152
+ const extraCookieSettings : ServerStateCookieOptions = {
153
+ isSecure : this . config . cookie . secure ,
154
+ isSameSite : this . config . cookie . isSameSite ,
155
+ password : this . config . cookie . password ,
156
+ domain : this . config . cookie . domain ,
157
+ path : this . coreSetup . http . basePath . serverBasePath || '/' ,
158
+ clearInvalid : false ,
159
+ isHttpOnly : true ,
160
+ ignoreErrors : true ,
161
+ encoding : 'iron' , // Same as hapi auth cookie
162
+ } ;
163
+
164
+ for ( let i = 1 ; i <= this . config . openid ! . extra_storage . additional_cookies ; i ++ ) {
165
+ hapiServer . states . add ( extraCookiePrefix + i , extraCookieSettings ) ;
166
+ }
167
+ }
168
+
169
+ private getExtraAuthStorageOptions ( ) : ExtraAuthStorageOptions {
170
+ // If we're here, we will always have the openid configuration
171
+ return {
172
+ cookiePrefix : this . config . openid ! . extra_storage . cookie_prefix ,
173
+ additionalCookies : this . config . openid ! . extra_storage . additional_cookies ,
174
+ logger : this . logger ,
175
+ } ;
176
+ }
177
+
138
178
requestIncludesAuthInfo ( request : OpenSearchDashboardsRequest ) : boolean {
139
179
return request . headers . authorization ? true : false ;
140
180
}
@@ -144,27 +184,37 @@ export class OpenIdAuthentication extends AuthenticationType {
144
184
}
145
185
146
186
getCookie ( request : OpenSearchDashboardsRequest , authInfo : any ) : SecuritySessionCookie {
187
+ setExtraAuthStorage (
188
+ request ,
189
+ request . headers . authorization as string ,
190
+ this . getExtraAuthStorageOptions ( )
191
+ ) ;
192
+
147
193
return {
148
194
username : authInfo . user_name ,
149
195
credentials : {
150
- authHeaderValue : request . headers . authorization ,
196
+ authHeaderValueExtra : true ,
151
197
} ,
152
198
authType : this . type ,
153
199
expiryTime : Date . now ( ) + this . config . session . ttl ,
154
200
} ;
155
201
}
156
202
157
203
// TODO: Add token expiration check here
158
- async isValidCookie ( cookie : SecuritySessionCookie ) : Promise < boolean > {
204
+ async isValidCookie (
205
+ cookie : SecuritySessionCookie ,
206
+ request : OpenSearchDashboardsRequest
207
+ ) : Promise < boolean > {
159
208
if (
160
209
cookie . authType !== this . type ||
161
210
! cookie . username ||
162
211
! cookie . expiryTime ||
163
- ! cookie . credentials ?. authHeaderValue ||
212
+ ( ! cookie . credentials ?. authHeaderValue && ! this . getExtraAuthStorageValue ( request , cookie ) ) ||
164
213
! cookie . credentials ?. expires_at
165
214
) {
166
215
return false ;
167
216
}
217
+
168
218
if ( cookie . credentials ?. expires_at > Date . now ( ) ) {
169
219
return true ;
170
220
}
@@ -187,10 +237,17 @@ export class OpenIdAuthentication extends AuthenticationType {
187
237
// if no id_token from refresh token call, maybe the Idp doesn't allow refresh id_token
188
238
if ( refreshTokenResponse . idToken ) {
189
239
cookie . credentials = {
190
- authHeaderValue : `Bearer ${ refreshTokenResponse . idToken } ` ,
240
+ authHeaderValueExtra : true ,
191
241
refresh_token : refreshTokenResponse . refreshToken ,
192
242
expires_at : getExpirationDate ( refreshTokenResponse ) , // expiresIn is in second
193
243
} ;
244
+
245
+ setExtraAuthStorage (
246
+ request ,
247
+ `Bearer ${ refreshTokenResponse . idToken } ` ,
248
+ this . getExtraAuthStorageOptions ( )
249
+ ) ;
250
+
194
251
return true ;
195
252
} else {
196
253
return false ;
@@ -226,8 +283,37 @@ export class OpenIdAuthentication extends AuthenticationType {
226
283
}
227
284
}
228
285
229
- buildAuthHeaderFromCookie ( cookie : SecuritySessionCookie ) : any {
286
+ getExtraAuthStorageValue ( request : OpenSearchDashboardsRequest , cookie : SecuritySessionCookie ) {
287
+ let extraValue = '' ;
288
+ if ( ! cookie . credentials ?. authHeaderValueExtra ) {
289
+ return extraValue ;
290
+ }
291
+
292
+ try {
293
+ extraValue = getExtraAuthStorageValue ( request , this . getExtraAuthStorageOptions ( ) ) ;
294
+ } catch ( error ) {
295
+ this . logger . info ( error ) ;
296
+ }
297
+
298
+ return extraValue ;
299
+ }
300
+
301
+ buildAuthHeaderFromCookie (
302
+ cookie : SecuritySessionCookie ,
303
+ request : OpenSearchDashboardsRequest
304
+ ) : any {
230
305
const header : any = { } ;
306
+ if ( cookie . credentials . authHeaderValueExtra ) {
307
+ try {
308
+ const extraAuthStorageValue = this . getExtraAuthStorageValue ( request , cookie ) ;
309
+ header . authorization = extraAuthStorageValue ;
310
+ return header ;
311
+ } catch ( error ) {
312
+ this . logger . error ( error ) ;
313
+ // TODO Re-throw?
314
+ // throw error;
315
+ }
316
+ }
231
317
const authHeaderValue = cookie . credentials ?. authHeaderValue ;
232
318
if ( authHeaderValue ) {
233
319
header . authorization = authHeaderValue ;
0 commit comments