-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Move redirect support from IDP handler to specific handlers
- Loading branch information
Showing
24 changed files
with
350 additions
and
246 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { BadRequestHttpError } from '../../util/errors/BadRequestHttpError'; | ||
import { FoundHttpError } from '../../util/errors/FoundHttpError'; | ||
import type { InteractionHandlerInput } from './InteractionHandler'; | ||
import { InteractionHandler } from './InteractionHandler'; | ||
import type { InteractionCompleterInput, InteractionCompleter } from './util/InteractionCompleter'; | ||
|
||
/** | ||
* Abstract class for {@link InteractionHandler}s that need to call an {@link InteractionCompleter}. | ||
* This is required by handlers that handle IDP behaviour | ||
* and need to complete an OIDC interaction by redirecting back to the client, | ||
* such as when logging in. | ||
* | ||
* Calls the InteractionCompleter with the results returned by the helper function | ||
* and throw a corresponding {@link FoundHttpError}. | ||
*/ | ||
export abstract class CompletingInteractionHandler extends InteractionHandler { | ||
protected readonly interactionCompleter: InteractionCompleter; | ||
|
||
protected constructor(interactionCompleter: InteractionCompleter) { | ||
super(); | ||
this.interactionCompleter = interactionCompleter; | ||
} | ||
|
||
public async canHandle(input: InteractionHandlerInput): Promise<void> { | ||
await super.canHandle(input); | ||
if (!input.oidcInteraction) { | ||
throw new BadRequestHttpError( | ||
'This action can only be performed as part of an OIDC authentication flow.', | ||
{ errorCode: 'E0002' }, | ||
); | ||
} | ||
} | ||
|
||
public async handle(input: InteractionHandlerInput): Promise<never> { | ||
// Interaction is defined due to canHandle call | ||
const parameters = await this.getCompletionParameters(input as Required<InteractionHandlerInput>); | ||
const location = await this.interactionCompleter.handleSafe(parameters); | ||
throw new FoundHttpError(location); | ||
} | ||
|
||
/** | ||
* Generates the parameters necessary to call an InteractionCompleter. | ||
* @param input - The original input parameters to the `handle` function. | ||
*/ | ||
protected abstract getCompletionParameters(input: Required<InteractionHandlerInput>): | ||
Promise<InteractionCompleterInput>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,25 @@ | ||
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError'; | ||
import { readJsonStream } from '../../util/StreamUtil'; | ||
import { InteractionHandler } from './email-password/handler/InteractionHandler'; | ||
import type { InteractionCompleteResult, InteractionHandlerInput } from './email-password/handler/InteractionHandler'; | ||
import { CompletingInteractionHandler } from './CompletingInteractionHandler'; | ||
import type { InteractionHandlerInput } from './InteractionHandler'; | ||
import type { InteractionCompleter, InteractionCompleterInput } from './util/InteractionCompleter'; | ||
|
||
/** | ||
* Simple InteractionHttpHandler that sends the session accountId to the InteractionCompleter as webId. | ||
* This is relevant when a client already logged in this session and tries logging in again. | ||
*/ | ||
export class SessionHttpHandler extends InteractionHandler { | ||
public async handle({ operation, oidcInteraction }: InteractionHandlerInput): Promise<InteractionCompleteResult> { | ||
if (!oidcInteraction?.session) { | ||
export class SessionHttpHandler extends CompletingInteractionHandler { | ||
public constructor(interactionCompleter: InteractionCompleter) { | ||
super(interactionCompleter); | ||
} | ||
|
||
protected async getCompletionParameters({ operation, oidcInteraction }: Required<InteractionHandlerInput>): | ||
Promise<InteractionCompleterInput> { | ||
if (!oidcInteraction.session) { | ||
throw new NotImplementedHttpError('Only interactions with a valid session are supported.'); | ||
} | ||
|
||
const { remember } = await readJsonStream(operation.body.data); | ||
return { | ||
type: 'complete', | ||
details: { webId: oidcInteraction.session.accountId, shouldRemember: Boolean(remember) }, | ||
}; | ||
return { oidcInteraction, webId: oidcInteraction.session.accountId, shouldRemember: Boolean(remember) }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
src/identity/interaction/email-password/handler/RegistrationHandler.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
src/identity/interaction/email-password/handler/ResetPasswordHandler.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import type { InteractionResults } from 'oidc-provider'; | ||
import type { InteractionCompleterInput } from './InteractionCompleter'; | ||
import { InteractionCompleter } from './InteractionCompleter'; | ||
|
||
/** | ||
* Creates a simple InteractionResults object based on the input parameters and injects it in the Interaction. | ||
*/ | ||
export class BaseInteractionCompleter extends InteractionCompleter { | ||
public async handle(input: InteractionCompleterInput): Promise<string> { | ||
const now = Math.floor(Date.now() / 1000); | ||
const result: InteractionResults = { | ||
login: { | ||
account: input.webId, | ||
// Indicates if a persistent cookie should be used instead of a session cookie. | ||
remember: input.shouldRemember, | ||
ts: now, | ||
}, | ||
consent: { | ||
// When OIDC clients want a refresh token, they need to request the 'offline_access' scope. | ||
// This indicates that this scope is not granted to the client in case they do not want to be remembered. | ||
rejectedScopes: input.shouldRemember ? [] : [ 'offline_access' ], | ||
}, | ||
}; | ||
|
||
// Generates the URL a client needs to be redirected to | ||
// after a successful interaction completion (such as logging in). | ||
// Identical behaviour to calling `provider.interactionResult`. | ||
// We use the code below instead of calling that function | ||
// since that function also uses Request/Response objects to generate the Interaction object, | ||
// which we already have here. | ||
const { oidcInteraction } = input; | ||
oidcInteraction.result = { ...oidcInteraction.lastSubmission, ...result }; | ||
await oidcInteraction.save(oidcInteraction.exp - now); | ||
|
||
return oidcInteraction.returnTo; | ||
} | ||
} |
Oops, something went wrong.