Merge branch 'release/16.4' into v16/dev
This commit is contained in:
@@ -77,6 +77,41 @@ export class RedirectRequestHandler extends AuthorizationRequestHandler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup all stale authorization requests and configurations from storage.
|
||||||
|
* This scans localStorage for any keys matching the appauth patterns and removes them,
|
||||||
|
* including the authorization request handle key.
|
||||||
|
*/
|
||||||
|
public cleanupStaleAuthorizationData(): Promise<void> {
|
||||||
|
// Check if we're in a browser environment with localStorage
|
||||||
|
if (typeof window === 'undefined' || !window.localStorage) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
const keysToRemove: string[] = [];
|
||||||
|
|
||||||
|
// Scan localStorage for all appauth-related keys
|
||||||
|
for (let i = 0; i < window.localStorage.length; i++) {
|
||||||
|
const key = window.localStorage.key(i);
|
||||||
|
if (
|
||||||
|
key &&
|
||||||
|
(key.includes('_appauth_authorization_request') ||
|
||||||
|
key.includes('_appauth_authorization_service_configuration') ||
|
||||||
|
key === AUTHORIZATION_REQUEST_HANDLE_KEY)
|
||||||
|
) {
|
||||||
|
keysToRemove.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all found stale keys
|
||||||
|
const removePromises = keysToRemove.map((key) => this.storageBackend.removeItem(key));
|
||||||
|
return Promise.all(removePromises).then(() => {
|
||||||
|
if (keysToRemove.length > 0) {
|
||||||
|
log(`Cleaned up ${keysToRemove.length} stale authorization data entries`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to introspect the contents of storage backend and completes the
|
* Attempts to introspect the contents of storage backend and completes the
|
||||||
* request.
|
* request.
|
||||||
@@ -119,12 +154,8 @@ export class RedirectRequestHandler extends AuthorizationRequestHandler {
|
|||||||
} else {
|
} else {
|
||||||
authorizationResponse = new AuthorizationResponse({ code: code, state: state });
|
authorizationResponse = new AuthorizationResponse({ code: code, state: state });
|
||||||
}
|
}
|
||||||
// cleanup state
|
// cleanup all authorization data including current and stale entries
|
||||||
return Promise.all([
|
return this.cleanupStaleAuthorizationData().then(() => {
|
||||||
this.storageBackend.removeItem(AUTHORIZATION_REQUEST_HANDLE_KEY),
|
|
||||||
this.storageBackend.removeItem(authorizationRequestKey(handle)),
|
|
||||||
this.storageBackend.removeItem(authorizationServiceConfigurationKey(handle)),
|
|
||||||
]).then(() => {
|
|
||||||
log('Delivering authorization response');
|
log('Delivering authorization response');
|
||||||
return {
|
return {
|
||||||
request: request,
|
request: request,
|
||||||
@@ -134,7 +165,10 @@ export class RedirectRequestHandler extends AuthorizationRequestHandler {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
log('Mismatched request (state and request_uri) dont match.');
|
log('Mismatched request (state and request_uri) dont match.');
|
||||||
return Promise.resolve(null);
|
// cleanup all authorization data even on mismatch to prevent stale PKCE data
|
||||||
|
return this.cleanupStaleAuthorizationData().then(() => {
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -247,6 +247,10 @@ export class UmbAuthFlow {
|
|||||||
|
|
||||||
// clear the internal state
|
// clear the internal state
|
||||||
this.#tokenResponse.setValue(undefined);
|
this.#tokenResponse.setValue(undefined);
|
||||||
|
|
||||||
|
// Also cleanup any OAuth/PKCE artifacts that may still be in localStorage
|
||||||
|
// This is a defense-in-depth measure during logout
|
||||||
|
await this.#authorizationHandler.cleanupStaleAuthorizationData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user