mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat!: remove caching from AgentGroupAccessChecker
This commit is contained in:
parent
4d1bd93e94
commit
3c43d046ef
@ -4,23 +4,7 @@
|
|||||||
{
|
{
|
||||||
"comment": "Checks if the agent belongs to a group that has access.",
|
"comment": "Checks if the agent belongs to a group that has access.",
|
||||||
"@id": "urn:solid-server:default:AgentGroupAccessChecker",
|
"@id": "urn:solid-server:default:AgentGroupAccessChecker",
|
||||||
"@type": "AgentGroupAccessChecker",
|
"@type": "AgentGroupAccessChecker"
|
||||||
"cache": {
|
|
||||||
"@id": "urn:solid-server:default:ExpiringAclCache",
|
|
||||||
"@type": "WrappedExpiringStorage",
|
|
||||||
"source": { "@type": "MemoryMapStorage" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"comment": "Makes sure the expiring storage cleanup timer is stopped when the application needs to stop.",
|
|
||||||
"@id": "urn:solid-server:default:Finalizer",
|
|
||||||
"@type": "ParallelHandler",
|
|
||||||
"handlers": [
|
|
||||||
{
|
|
||||||
"@type": "FinalizableHandler",
|
|
||||||
"finalizable": { "@id": "urn:solid-server:default:ExpiringAclCache" }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { Store, Term } from 'n3';
|
import type { Store, Term } from 'n3';
|
||||||
import type { ResourceIdentifier } from '../../http/representation/ResourceIdentifier';
|
import type { ResourceIdentifier } from '../../http/representation/ResourceIdentifier';
|
||||||
import type { ExpiringStorage } from '../../storage/keyvalue/ExpiringStorage';
|
|
||||||
import { fetchDataset } from '../../util/FetchUtil';
|
import { fetchDataset } from '../../util/FetchUtil';
|
||||||
import { promiseSome } from '../../util/PromiseUtil';
|
import { promiseSome } from '../../util/PromiseUtil';
|
||||||
import { readableToQuads } from '../../util/StreamUtil';
|
import { readableToQuads } from '../../util/StreamUtil';
|
||||||
@ -11,20 +10,10 @@ import { AccessChecker } from './AccessChecker';
|
|||||||
/**
|
/**
|
||||||
* Checks if the given WebID belongs to a group that has access.
|
* Checks if the given WebID belongs to a group that has access.
|
||||||
* Implements the behaviour of groups from the WAC specification.
|
* Implements the behaviour of groups from the WAC specification.
|
||||||
*
|
|
||||||
* Fetched results will be stored in an ExpiringStorage.
|
|
||||||
*
|
|
||||||
* Requires a storage that can store JS objects.
|
|
||||||
* `expiration` parameter is how long entries in the cache should be stored in seconds, defaults to 3600.
|
|
||||||
*/
|
*/
|
||||||
export class AgentGroupAccessChecker extends AccessChecker {
|
export class AgentGroupAccessChecker extends AccessChecker {
|
||||||
private readonly cache: ExpiringStorage<string, Promise<Store>>;
|
public constructor() {
|
||||||
private readonly expiration: number;
|
|
||||||
|
|
||||||
public constructor(cache: ExpiringStorage<string, Promise<Store>>, expiration = 3600) {
|
|
||||||
super();
|
super();
|
||||||
this.cache = cache;
|
|
||||||
this.expiration = expiration * 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handle({ acl, rule, credential }: AccessCheckerArgs): Promise<boolean> {
|
public async handle({ acl, rule, credential }: AccessCheckerArgs): Promise<boolean> {
|
||||||
@ -49,24 +38,18 @@ export class AgentGroupAccessChecker extends AccessChecker {
|
|||||||
const groupDocument: ResourceIdentifier = { path: /^[^#]*/u.exec(group.value)![0] };
|
const groupDocument: ResourceIdentifier = { path: /^[^#]*/u.exec(group.value)![0] };
|
||||||
|
|
||||||
// Fetch the required vCard group file
|
// Fetch the required vCard group file
|
||||||
const quads = await this.fetchCachedQuads(groupDocument.path);
|
const quads = await this.fetchQuads(groupDocument.path);
|
||||||
return quads.countQuads(group, VCARD.terms.hasMember, webId, null) !== 0;
|
return quads.countQuads(group, VCARD.terms.hasMember, webId, null) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches quads from the given URL.
|
* Fetches quads from the given URL.
|
||||||
* Will cache the values for later re-use.
|
|
||||||
*/
|
*/
|
||||||
private async fetchCachedQuads(url: string): Promise<Store> {
|
private async fetchQuads(url: string): Promise<Store> {
|
||||||
let result = await this.cache.get(url);
|
const prom = (async(): Promise<Store> => {
|
||||||
if (!result) {
|
const representation = await fetchDataset(url);
|
||||||
const prom = (async(): Promise<Store> => {
|
return readableToQuads(representation.data);
|
||||||
const representation = await fetchDataset(url);
|
})();
|
||||||
return readableToQuads(representation.data);
|
return await prom;
|
||||||
})();
|
|
||||||
await this.cache.set(url, prom, this.expiration);
|
|
||||||
result = await prom;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ import type { AccessCheckerArgs } from '../../../../src/authorization/access/Acc
|
|||||||
import { AgentGroupAccessChecker } from '../../../../src/authorization/access/AgentGroupAccessChecker';
|
import { AgentGroupAccessChecker } from '../../../../src/authorization/access/AgentGroupAccessChecker';
|
||||||
import { BasicRepresentation } from '../../../../src/http/representation/BasicRepresentation';
|
import { BasicRepresentation } from '../../../../src/http/representation/BasicRepresentation';
|
||||||
import type { Representation } from '../../../../src/http/representation/Representation';
|
import type { Representation } from '../../../../src/http/representation/Representation';
|
||||||
import type { ExpiringStorage } from '../../../../src/storage/keyvalue/ExpiringStorage';
|
|
||||||
import { INTERNAL_QUADS } from '../../../../src/util/ContentTypes';
|
import { INTERNAL_QUADS } from '../../../../src/util/ContentTypes';
|
||||||
import * as fetchUtil from '../../../../src/util/FetchUtil';
|
import * as fetchUtil from '../../../../src/util/FetchUtil';
|
||||||
import { ACL, VCARD } from '../../../../src/util/Vocabularies';
|
import { ACL, VCARD } from '../../../../src/util/Vocabularies';
|
||||||
@ -17,7 +16,6 @@ describe('An AgentGroupAccessChecker', (): void => {
|
|||||||
acl.addQuad(namedNode('noMatch'), ACL.terms.agentGroup, namedNode('badGroup'));
|
acl.addQuad(namedNode('noMatch'), ACL.terms.agentGroup, namedNode('badGroup'));
|
||||||
let fetchMock: jest.SpyInstance;
|
let fetchMock: jest.SpyInstance;
|
||||||
let representation: Representation;
|
let representation: Representation;
|
||||||
let cache: ExpiringStorage<string, Promise<Store>>;
|
|
||||||
let checker: AgentGroupAccessChecker;
|
let checker: AgentGroupAccessChecker;
|
||||||
|
|
||||||
beforeEach(async(): Promise<void> => {
|
beforeEach(async(): Promise<void> => {
|
||||||
@ -27,9 +25,7 @@ describe('An AgentGroupAccessChecker', (): void => {
|
|||||||
fetchMock.mockResolvedValue(representation);
|
fetchMock.mockResolvedValue(representation);
|
||||||
fetchMock.mockClear();
|
fetchMock.mockClear();
|
||||||
|
|
||||||
cache = new Map() as any;
|
checker = new AgentGroupAccessChecker();
|
||||||
|
|
||||||
checker = new AgentGroupAccessChecker(cache);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle all requests.', async(): Promise<void> => {
|
it('can handle all requests.', async(): Promise<void> => {
|
||||||
@ -50,11 +46,4 @@ describe('An AgentGroupAccessChecker', (): void => {
|
|||||||
const input: AccessCheckerArgs = { acl, rule: namedNode('groupMatch'), credential: {}};
|
const input: AccessCheckerArgs = { acl, rule: namedNode('groupMatch'), credential: {}};
|
||||||
await expect(checker.handle(input)).resolves.toBe(false);
|
await expect(checker.handle(input)).resolves.toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('caches fetched results.', async(): Promise<void> => {
|
|
||||||
const input: AccessCheckerArgs = { acl, rule: namedNode('groupMatch'), credential: { webId }};
|
|
||||||
await expect(checker.handle(input)).resolves.toBe(true);
|
|
||||||
await expect(checker.handle(input)).resolves.toBe(true);
|
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user