-
Notifications
You must be signed in to change notification settings - Fork 46
[WIP] fix: correctly respect client expiry #2122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
4511050
chore: add test:debug helper script
ThisIsMissEm b6a8f13
chore: use file:.. dependencies for demoClientApp
ThisIsMissEm c9b4393
chore: use brokers with trailing slash in browser demoClientApp
ThisIsMissEm 1a32dbd
WIP: Initial implementation
ThisIsMissEm 8f6b521
refactor: create dedicated dynamic client registrar class
ThisIsMissEm 3d9851a
refactor: add isValidUrl utility method to core
ThisIsMissEm ed4eaba
refactor: add isObject util to core
ThisIsMissEm e532fc7
WIP: clean up StorageUtility changes
ThisIsMissEm d4f803c
refactor: split client storage from user data
ThisIsMissEm abce024
refactor: change IClient interface to be a discriminated union of dif…
ThisIsMissEm 4570438
refactor: add isValidClient validator & type guard
ThisIsMissEm 04190d0
WIP: dedicated Client Manager class
ThisIsMissEm 298563d
WIP: support overrides for mockIssuerConfig
ThisIsMissEm 0e59c35
WIP: browser work
ThisIsMissEm 021ec07
refactor: fix oidc-ext to handle new types from authn-core
ThisIsMissEm 0f636ba
refactor: move negotiateClientSigningAlg to core
ThisIsMissEm 94daee1
WIP: node work
ThisIsMissEm 422e188
WIP: implement client manager
ThisIsMissEm 99ccdc8
refactor: improve types for DynamicClientRegistrar
ThisIsMissEm 77f07bd
WIP: add client manager to browser
ThisIsMissEm 1411f7f
WIP: re-implement login & restore session
ThisIsMissEm 107d1fc
WIP: remove browser client registrar
ThisIsMissEm 5202c85
WIP: fix issues in PKCE flow
ThisIsMissEm 29852ed
refactor: check client expiry as part of validation
ThisIsMissEm cf33ddb
WIP: improve core types
ThisIsMissEm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 |
---|---|---|
|
@@ -30,20 +30,38 @@ import { | |
IIncomingRedirectHandler, | ||
ISessionInfo, | ||
ISessionInfoManager, | ||
IIssuerConfigFetcher, | ||
ISessionInternalInfo, | ||
ILoginOptions, | ||
IPublicIdentifierClientOptions, | ||
IDynamicClientOptions, | ||
EVENTS, | ||
ClientManager, | ||
isValidUrl, | ||
} from "@inrupt/solid-client-authn-core"; | ||
import { removeOidcQueryParam } from "@inrupt/oidc-client-ext"; | ||
import { EventEmitter } from "events"; | ||
|
||
import { KEY_CURRENT_URL } from "./constant"; | ||
|
||
// By only referring to `window` at runtime, apps that do server-side rendering | ||
// won't run into errors when rendering code that instantiates a | ||
// ClientAuthentication: | ||
const globalFetch: typeof window.fetch = (request, init) => | ||
window.fetch(request, init); | ||
|
||
export type IClientOptions = | ||
| IPublicIdentifierClientOptions | ||
| IDynamicClientOptions; | ||
export type ILoginOptions = IClientOptions & { | ||
sessionId: string; | ||
oidcIssuer: string; | ||
redirectUrl: string; | ||
tokenType?: "DPoP" | "Bearer" = "DPoP"; | ||
}; | ||
|
||
export interface ISilentLoginOptions { | ||
sessionId: string; | ||
} | ||
|
||
/** | ||
* @hidden | ||
*/ | ||
|
@@ -53,39 +71,86 @@ export default class ClientAuthentication { | |
private redirectHandler: IIncomingRedirectHandler, | ||
private logoutHandler: ILogoutHandler, | ||
private sessionInfoManager: ISessionInfoManager, | ||
private issuerConfigFetcher: IIssuerConfigFetcher | ||
private clientManager: ClientManager | ||
) {} | ||
|
||
// Define these functions as properties so that they don't get accidentally re-bound. | ||
// Isn't Javascript fun? | ||
// login = async ( | ||
// options: ILoginOptions, | ||
// eventEmitter: EventEmitter | ||
// ): Promise<void> => { | ||
// // In order to get a clean start, make sure that the session is logged out | ||
// // on login. | ||
// // But we may want to preserve our client application info, particularly if | ||
// // we used Dynamic Client Registration to register (since we don't | ||
// // necessarily want the user to have to register this app each time they | ||
// // login). | ||
// // FIXME: now preserves the client, but deletes the session info: | ||
// await this.sessionInfoManager.clear(options.sessionId); | ||
|
||
// // In the case of the user hitting the 'back' button in their browser, they | ||
// // could return to a previous redirect URL that contains OIDC params that | ||
// // are now longer valid - so just to be safe, strip relevant params now. | ||
// const redirectUrl = removeOidcQueryParam( | ||
// options.redirectUrl ?? window.location.href | ||
// ); | ||
|
||
// await this.loginHandler.handle({ | ||
// ...options, | ||
// redirectUrl, | ||
// // If no clientName is provided, the clientId may be used instead. | ||
// clientName: options.clientName ?? options.clientId, | ||
// eventEmitter, | ||
// }); | ||
// }; | ||
|
||
login = async ( | ||
sessionId: string, | ||
options: ILoginOptions, | ||
eventEmitter: EventEmitter | ||
): Promise<void> => { | ||
// In order to get a clean start, make sure that the session is logged out | ||
// on login. | ||
// But we may want to preserve our client application info, particularly if | ||
// we used Dynamic Client Registration to register (since we don't | ||
// necessarily want the user to have to register this app each time they | ||
// login). | ||
await this.sessionInfoManager.clear(options.sessionId); | ||
|
||
// In the case of the user hitting the 'back' button in their browser, they | ||
// could return to a previous redirect URL that contains OIDC params that | ||
// are now longer valid - so just to be safe, strip relevant params now. | ||
const redirectUrl = removeOidcQueryParam( | ||
options.redirectUrl ?? window.location.href | ||
); | ||
|
||
await this.loginHandler.handle({ | ||
...options, | ||
const { oidcIssuer, ...clientOptions } = options; | ||
|
||
// TODO: Should we validate presence of oidcIssuer and redirectUrl here? | ||
|
||
const redirectUrl = | ||
options.redirectUrl && isValidUrl(options.redirectUrl) | ||
? options.redirectUrl | ||
: window.location.href; | ||
|
||
this.loginHandler.handle({ | ||
sessionId, | ||
oidcIssuer, | ||
redirectUrl, | ||
// If no clientName is provided, the clientId may be used instead. | ||
clientName: options.clientName ?? options.clientId, | ||
eventEmitter, | ||
}); | ||
}; | ||
|
||
silentlyLogin = async (options: ISilentLoginOptions): Promise<boolean> => { | ||
// FIXME: Implement | ||
const sessionInfo = await this.sessionInfoManager.get(options.sessionId); | ||
|
||
if (sessionInfo === undefined || sessionInfo.issuer === undefined) { | ||
return false; | ||
} | ||
|
||
const client = await this.clientManager.get(sessionInfo.issuer); | ||
|
||
if (!client) { | ||
return false; | ||
} | ||
|
||
// FIXME: use storage adapter: | ||
window.localStorage.setItem(KEY_CURRENT_URL, window.location.href); | ||
|
||
// await this.loginHandler.handle({ | ||
// oidcIssuer: sessionInfo.issuer, | ||
// redirectUrl: sessionInfo.redirectUrl, | ||
// }); | ||
|
||
return false; | ||
}; | ||
|
||
// By default, our fetch() resolves to the environment fetch() function. | ||
fetch = globalFetch; | ||
|
||
|
@@ -112,17 +177,16 @@ export default class ClientAuthentication { | |
// if the expected information cannot be found. | ||
// Note that the ID token is not stored, which means the session information | ||
// cannot be validated at this point. | ||
// FIXME: not actually part of the public interface: | ||
validateCurrentSession = async ( | ||
currentSessionId: string | ||
): Promise<(ISessionInfo & ISessionInternalInfo) | null> => { | ||
const sessionInfo = await this.sessionInfoManager.get(currentSessionId); | ||
if ( | ||
sessionInfo === undefined || | ||
sessionInfo.clientAppId === undefined || | ||
sessionInfo.issuer === undefined | ||
) { | ||
|
||
if (sessionInfo === undefined) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sessionInfo is undefined if the issuer is undefined, and clientAppId is no longer used here (see splitting sessionInfoManager and ClientRegistrar) |
||
return null; | ||
} | ||
|
||
return sessionInfo; | ||
}; | ||
|
||
|
@@ -162,6 +226,7 @@ export default class ClientAuthentication { | |
} | ||
}; | ||
|
||
// FIXME: technically should be the same as removeOidcQueryParam method, though isn't: | ||
private cleanUrlAfterRedirect(url: string): void { | ||
const cleanedUpUrl = new URL(url); | ||
cleanedUpUrl.searchParams.delete("state"); | ||
|
This file contains hidden or 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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the changes in this file are relevant anymore: