@@ -144,6 +144,62 @@ export default abstract class BaseAPIAuthProvider extends BaseAuthProvider {
144144 } ) ;
145145 }
146146
147+ public verifyOIDCStateParam ( stateToTest : string | null ) : boolean {
148+ const oidcState = sessionStorage . getItem ( 'oidcState' ) ;
149+
150+ // TODO: should we verify if session storage has been cleared?
151+ if ( oidcState === null ) return true ;
152+
153+ if ( oidcState === stateToTest ) return true ;
154+
155+ document . dispatchEvent (
156+ new CustomEvent ( 'scigateway' , {
157+ detail : {
158+ type : NotificationType ,
159+ payload : {
160+ message :
161+ 'It is not possible to authenticate you at the moment. Please, try again later.' ,
162+ severity : 'error' ,
163+ } ,
164+ } ,
165+ } )
166+ ) ;
167+
168+ return false ;
169+ }
170+
171+ public async verifyOIDCNonce ( accessToken : string ) : Promise < boolean > {
172+ const oidcNonce = sessionStorage . getItem ( 'oidcNonce' ) ;
173+
174+ // TODO: should we verify if session storage has been cleared?
175+ if ( oidcNonce === null ) return true ;
176+
177+ const encryptedOIDCNonce =
178+ await generateCodeChallengeFromVerifier ( oidcNonce ) ;
179+
180+ const { nonce : nonceToTest } = JSON . parse ( parseJwt ( accessToken ) ) ;
181+
182+ if ( encryptedOIDCNonce === nonceToTest ) {
183+ return true ;
184+ }
185+
186+ log . error ( 'Nonce verification failed' ) ;
187+ document . dispatchEvent (
188+ new CustomEvent ( 'scigateway' , {
189+ detail : {
190+ type : NotificationType ,
191+ payload : {
192+ message :
193+ 'It is not possible to authenticate you at the moment. Please, try again later.' ,
194+ severity : 'error' ,
195+ } ,
196+ } ,
197+ } )
198+ ) ;
199+
200+ return false ;
201+ }
202+
147203 async pkceToken (
148204 token : string ,
149205 oidcProvider : InitialisedOIDCProvider
@@ -191,7 +247,15 @@ export default abstract class BaseAPIAuthProvider extends BaseAuthProvider {
191247 id_token = await this . nonPKCEToken ( token , oidcProvider ) ;
192248 }
193249
194- // TODO: sometimes login request fails here - maybe because it was too fast?
250+ if ( ! ( await this . verifyOIDCNonce ( id_token ) ) )
251+ throw Error ( 'Nonce verification failed' ) ;
252+
253+ // TODO: sometimes login request fails here because it was too fast
254+ // aka JWT iat is not yet "in the past"
255+ // need to talk to backend people about it
256+ await new Promise < void > ( ( resolve , _reject ) => {
257+ setTimeout ( ( ) => resolve ( ) , 1_000 ) ;
258+ } ) ;
195259
196260 const { data : jwt } = await axios . post (
197261 `${ this . authUrl } /oidc_login/${ oidcProvider . provider_id } ` ,
@@ -206,6 +270,8 @@ export default abstract class BaseAPIAuthProvider extends BaseAuthProvider {
206270 this . storeToken ( jwt ) ;
207271 sessionStorage . removeItem ( 'codeVerifier' ) ;
208272 sessionStorage . removeItem ( 'oidcProviderId' ) ;
273+ sessionStorage . removeItem ( 'oidcState' ) ;
274+ sessionStorage . removeItem ( 'oidcNonce' ) ;
209275 const payload : {
210276 sessionId : string ;
211277 username : string ;
@@ -220,16 +286,28 @@ export default abstract class BaseAPIAuthProvider extends BaseAuthProvider {
220286 }
221287 }
222288
223- public async setupOIDC ( oidcProvider : InitialisedOIDCProvider ) : Promise < void > {
289+ public async setupOIDC (
290+ oidcProvider : InitialisedOIDCProvider ,
291+ referrer ?: string
292+ ) : Promise < void > {
293+ console . log ( 'setupOIDC called' ) ;
224294 let codeChallenge : string | undefined ;
225295 if ( oidcProvider . pkce ) {
226296 const codeVerifier = generateCodeVerifier ( ) ;
227297 sessionStorage . setItem ( 'codeVerifier' , codeVerifier ) ;
228298 codeChallenge = await generateCodeChallengeFromVerifier ( codeVerifier ) ;
229299 }
230300 sessionStorage . setItem ( 'oidcProviderId' , oidcProvider . provider_id ) ;
301+ const state = generateCodeVerifier ( ) ;
302+ sessionStorage . setItem ( 'oidcState' , state ) ;
303+ const nonce = generateCodeVerifier ( ) ;
304+ const encryptedNonce = await generateCodeChallengeFromVerifier ( nonce ) ;
305+
306+ sessionStorage . setItem ( 'oidcNonce' , nonce ) ;
307+
308+ if ( referrer ) sessionStorage . setItem ( 'referrer' , referrer ) ;
231309
232- this . redirectUrl = `${ oidcProvider . authorization_endpoint } ?client_id=${ oidcProvider . client_id } &redirect_uri=${ window . location . origin } /login&response_type=code${ oidcProvider . pkce ? `&code_challenge_method=S256&code_challenge=${ codeChallenge } ` : '' } &scope=${ oidcProvider . scope } ` ;
310+ this . redirectUrl = `${ oidcProvider . authorization_endpoint } ?client_id=${ oidcProvider . client_id } &redirect_uri=${ window . location . origin } /login&response_type=code${ oidcProvider . pkce ? `&code_challenge_method=S256&code_challenge=${ codeChallenge } ` : '' } &scope=${ oidcProvider . scope } &state= ${ state } &nonce= ${ encryptedNonce } ` ;
233311 }
234312
235313 public async initialiseOIDCProviders ( ) : Promise < InitialisedOIDCProvider [ ] > {
0 commit comments