-
Notifications
You must be signed in to change notification settings - Fork 121
/
AcpServer.test.ts
138 lines (122 loc) · 5.57 KB
/
AcpServer.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import fetch from 'cross-fetch';
import { BasicRepresentation } from '../../src/http/representation/BasicRepresentation';
import type { App } from '../../src/init/App';
import type { ResourceStore } from '../../src/storage/ResourceStore';
import { joinUrl } from '../../src/util/PathUtil';
import { AcpHelper } from '../util/AcpHelper';
import { getPort } from '../util/Util';
import {
getDefaultVariables,
getPresetConfigPath,
getTestConfigPath,
getTestFolder,
instantiateFromConfig, removeFolder,
} from './Config';
const port = getPort('AcpServer');
const baseUrl = `http://localhost:${port}/`;
const rootFilePath = getTestFolder('full-config-acp');
const stores: [string, any][] = [
[ 'in-memory storage', {
storeConfig: 'storage/backend/memory.json',
teardown: jest.fn(),
}],
[ 'on-disk storage', {
storeConfig: 'storage/backend/file.json',
teardown: async(): Promise<void> => removeFolder(rootFilePath),
}],
];
describe.each(stores)('An LDP handler with ACP using %s', (name, { storeConfig, teardown }): void => {
let app: App;
let store: ResourceStore;
let acpHelper: AcpHelper;
beforeAll(async(): Promise<void> => {
const variables = {
...getDefaultVariables(port, baseUrl),
'urn:solid-server:default:variable:rootFilePath': rootFilePath,
};
// Create and start the server
const instances = await instantiateFromConfig(
'urn:solid-server:test:Instances',
[
getPresetConfigPath(storeConfig),
getTestConfigPath('ldp-with-acp.json'),
],
variables,
) as Record<string, any>;
({ app, store } = instances);
await app.start();
// Create test helper for manipulating acl
acpHelper = new AcpHelper(store);
});
afterAll(async(): Promise<void> => {
await teardown();
await app.stop();
});
it('provides no access if no ACRs are defined.', async(): Promise<void> => {
const response = await fetch(baseUrl);
expect(response.status).toBe(401);
});
it('provides access if the correct ACRs are defined.', async(): Promise<void> => {
await acpHelper.setAcp(baseUrl, acpHelper.createAcr({ resource: baseUrl,
policies: [ acpHelper.createPolicy({
allow: [ 'read' ],
anyOf: [ acpHelper.createMatcher({ publicAgent: true }) ],
}) ]}));
const response = await fetch(baseUrl);
expect(response.status).toBe(200);
});
it('uses ACP inheritance.', async(): Promise<void> => {
const target = joinUrl(baseUrl, 'foo');
await store.setRepresentation({ path: target }, new BasicRepresentation('test', 'text/plain'));
await acpHelper.setAcp(baseUrl, acpHelper.createAcr({ resource: baseUrl,
memberPolicies: [ acpHelper.createPolicy({
allow: [ 'read' ],
anyOf: [ acpHelper.createMatcher({ publicAgent: true }) ],
}) ]}));
await acpHelper.setAcp(target, acpHelper.createAcr({ resource: baseUrl,
policies: [ acpHelper.createPolicy({
allow: [ 'write' ],
anyOf: [ acpHelper.createMatcher({ publicAgent: true }) ],
}) ]}));
const response = await fetch(target);
expect(response.status).toBe(200);
});
it('requires control permissions to access ACRs.', async(): Promise<void> => {
const baseAcr = joinUrl(baseUrl, '.acr');
const turtle = acpHelper.toTurtle(acpHelper.createAcr({ resource: baseUrl,
policies: [ acpHelper.createPolicy({
allow: [ 'read' ],
anyOf: [ acpHelper.createMatcher({ publicAgent: true }) ],
}) ]}));
let response = await fetch(baseAcr);
expect(response.status).toBe(401);
response = await fetch(baseAcr, { method: 'PUT', headers: { 'content-type': 'text/turtle' }, body: turtle });
expect(response.status).toBe(401);
await acpHelper.setAcp(baseUrl, acpHelper.createAcr({ resource: baseUrl,
policies: [ acpHelper.createPolicy({
allow: [ 'control' ],
anyOf: [ acpHelper.createMatcher({ publicAgent: true }) ],
}) ]}));
response = await fetch(baseAcr);
expect(response.status).toBe(200);
response = await fetch(baseAcr, { method: 'PUT', headers: { 'content-type': 'text/turtle' }, body: turtle });
expect(response.status).toBe(205);
// Can now also read root container due to updated permissions
response = await fetch(baseUrl);
expect(response.status).toBe(200);
});
it('returns the required Link headers.', async(): Promise<void> => {
const baseAcr = joinUrl(baseUrl, '.acr');
const response = await fetch(baseAcr, { method: 'OPTIONS' });
const linkHeaders = response.headers.get('link');
expect(linkHeaders).toContain('<http://www.w3.org/ns/solid/acp#AccessControlResource>; rel="type"');
expect(linkHeaders).toContain('<http://www.w3.org/ns/auth/acl#Read>; rel="http://www.w3.org/ns/solid/acp#grant"');
expect(linkHeaders).toContain('<http://www.w3.org/ns/auth/acl#Append>; rel="http://www.w3.org/ns/solid/acp#grant"');
expect(linkHeaders).toContain('<http://www.w3.org/ns/auth/acl#Write>; rel="http://www.w3.org/ns/solid/acp#grant"');
expect(linkHeaders).toContain('<http://www.w3.org/ns/auth/acl#Control>; rel="http://www.w3.org/ns/solid/acp#grant"');
expect(linkHeaders).toContain('<http://www.w3.org/ns/solid/acp#target>; rel="http://www.w3.org/ns/solid/acp#attribute"');
expect(linkHeaders).toContain('<http://www.w3.org/ns/solid/acp#agent>; rel="http://www.w3.org/ns/solid/acp#attribute"');
expect(linkHeaders).toContain('<http://www.w3.org/ns/solid/acp#client>; rel="http://www.w3.org/ns/solid/acp#attribute"');
expect(linkHeaders).toContain('<http://www.w3.org/ns/solid/acp#issuer>; rel="http://www.w3.org/ns/solid/acp#attribute"');
});
});