mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
test: Use Components.js in Authorization.
This commit is contained in:
parent
d1d29a3f52
commit
1cf1167261
@ -6,12 +6,14 @@
|
|||||||
"@type": "SequenceHandler",
|
"@type": "SequenceHandler",
|
||||||
"SequenceHandler:_handlers": [
|
"SequenceHandler:_handlers": [
|
||||||
{
|
{
|
||||||
|
"@id": "urn:solid-server:default:LoggerInitializer",
|
||||||
"@type": "LoggerInitializer",
|
"@type": "LoggerInitializer",
|
||||||
"LoggerInitializer:_loggerFactory": {
|
"LoggerInitializer:_loggerFactory": {
|
||||||
"@id": "urn:solid-server:default:LoggerFactory"
|
"@id": "urn:solid-server:default:LoggerFactory"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"@id": "urn:solid-server:default:RootContainerInitializer",
|
||||||
"@type": "RootContainerInitializer",
|
"@type": "RootContainerInitializer",
|
||||||
"RootContainerInitializer:_baseUrl": {
|
"RootContainerInitializer:_baseUrl": {
|
||||||
"@id": "urn:solid-server:default:variable:baseUrl"
|
"@id": "urn:solid-server:default:variable:baseUrl"
|
||||||
@ -21,6 +23,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"@id": "urn:solid-server:default:AclInitializer",
|
||||||
"@type": "AclInitializer",
|
"@type": "AclInitializer",
|
||||||
"AclInitializer:_baseUrl": {
|
"AclInitializer:_baseUrl": {
|
||||||
"@id": "urn:solid-server:default:variable:baseUrl"
|
"@id": "urn:solid-server:default:variable:baseUrl"
|
||||||
@ -33,6 +36,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"@id": "urn:solid-server:default:ServerInitializer",
|
||||||
"@type": "ServerInitializer",
|
"@type": "ServerInitializer",
|
||||||
"ServerInitializer:_serverFactory": {
|
"ServerInitializer:_serverFactory": {
|
||||||
"@id": "urn:solid-server:default:ServerFactory"
|
"@id": "urn:solid-server:default:ServerFactory"
|
||||||
|
@ -131,7 +131,7 @@ export class WebAclAuthorizer extends Authorizer {
|
|||||||
if (error instanceof NotFoundHttpError) {
|
if (error instanceof NotFoundHttpError) {
|
||||||
this.logger.debug(`No direct ACL document found for ${id.path}`);
|
this.logger.debug(`No direct ACL document found for ${id.path}`);
|
||||||
} else {
|
} else {
|
||||||
this.logger.error(`Error reading ACL for ${id.path}`, { error });
|
this.logger.error(`Error reading ACL for ${id.path}: ${(error as Error).message}`, { error });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { getLoggerFor } from '../logging/LogUtil';
|
|||||||
import type { ResourceStore } from '../storage/ResourceStore';
|
import type { ResourceStore } from '../storage/ResourceStore';
|
||||||
import { TEXT_TURTLE } from '../util/ContentTypes';
|
import { TEXT_TURTLE } from '../util/ContentTypes';
|
||||||
import { NotFoundHttpError } from '../util/errors/NotFoundHttpError';
|
import { NotFoundHttpError } from '../util/errors/NotFoundHttpError';
|
||||||
|
import { ensureTrailingSlash } from '../util/PathUtil';
|
||||||
import { guardedStreamFrom } from '../util/StreamUtil';
|
import { guardedStreamFrom } from '../util/StreamUtil';
|
||||||
import { CONTENT_TYPE } from '../util/UriConstants';
|
import { CONTENT_TYPE } from '../util/UriConstants';
|
||||||
import { Initializer } from './Initializer';
|
import { Initializer } from './Initializer';
|
||||||
@ -24,7 +25,7 @@ export class AclInitializer extends Initializer {
|
|||||||
aclManager: AclManager,
|
aclManager: AclManager,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = ensureTrailingSlash(baseUrl);
|
||||||
this.store = store;
|
this.store = store;
|
||||||
this.aclManager = aclManager;
|
this.aclManager = aclManager;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,13 @@ import { isResourceIdentifier } from './ResourceIdentifier';
|
|||||||
export type MetadataIdentifier = ResourceIdentifier | NamedNode | BlankNode;
|
export type MetadataIdentifier = ResourceIdentifier | NamedNode | BlankNode;
|
||||||
export type MetadataOverrideValue = NamedNode | Literal | string | (NamedNode | Literal | string)[];
|
export type MetadataOverrideValue = NamedNode | Literal | string | (NamedNode | Literal | string)[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the object is a `RepresentationMetadata`.
|
||||||
|
*/
|
||||||
|
export const isRepresentationMetadata = function(object: any): object is RepresentationMetadata {
|
||||||
|
return typeof object?.setMetadata === 'function';
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the metadata triples and provides methods for easy access.
|
* Stores the metadata triples and provides methods for easy access.
|
||||||
* Most functions return the metadata object to allow for chaining.
|
* Most functions return the metadata object to allow for chaining.
|
||||||
@ -49,7 +56,7 @@ export class RepresentationMetadata {
|
|||||||
this.id = DataFactory.namedNode(input.path);
|
this.id = DataFactory.namedNode(input.path);
|
||||||
} else if (isTerm(input)) {
|
} else if (isTerm(input)) {
|
||||||
this.id = input;
|
this.id = input;
|
||||||
} else if (input instanceof RepresentationMetadata) {
|
} else if (isRepresentationMetadata(input)) {
|
||||||
this.id = input.identifier;
|
this.id = input.identifier;
|
||||||
this.addQuads(input.quads());
|
this.addQuads(input.quads());
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier';
|
import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier';
|
||||||
|
import { getLoggerFor } from '../../logging/LogUtil';
|
||||||
import { InternalServerError } from '../errors/InternalServerError';
|
import { InternalServerError } from '../errors/InternalServerError';
|
||||||
import { ensureTrailingSlash } from '../PathUtil';
|
import { ensureTrailingSlash } from '../PathUtil';
|
||||||
import type { IdentifierStrategy } from './IdentifierStrategy';
|
import type { IdentifierStrategy } from './IdentifierStrategy';
|
||||||
@ -8,13 +9,18 @@ import type { IdentifierStrategy } from './IdentifierStrategy';
|
|||||||
*/
|
*/
|
||||||
export class SingleRootIdentifierStrategy implements IdentifierStrategy {
|
export class SingleRootIdentifierStrategy implements IdentifierStrategy {
|
||||||
private readonly baseUrl: string;
|
private readonly baseUrl: string;
|
||||||
|
protected readonly logger = getLoggerFor(this);
|
||||||
|
|
||||||
public constructor(baseUrl: string) {
|
public constructor(baseUrl: string) {
|
||||||
this.baseUrl = ensureTrailingSlash(baseUrl);
|
this.baseUrl = ensureTrailingSlash(baseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public supportsIdentifier(identifier: ResourceIdentifier): boolean {
|
public supportsIdentifier(identifier: ResourceIdentifier): boolean {
|
||||||
return identifier.path.startsWith(this.baseUrl);
|
const supported = identifier.path.startsWith(this.baseUrl);
|
||||||
|
this.logger.debug(supported ?
|
||||||
|
`Identifier ${identifier.path} is part of ${this.baseUrl}` :
|
||||||
|
`Identifier ${identifier.path} is not part of ${this.baseUrl}`);
|
||||||
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getParentContainer(identifier: ResourceIdentifier): ResourceIdentifier {
|
public getParentContainer(identifier: ResourceIdentifier): ResourceIdentifier {
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import type {
|
|
||||||
HttpHandler,
|
|
||||||
ResourceStore,
|
|
||||||
} from '../../src/index';
|
|
||||||
import {
|
|
||||||
AuthenticatedLdpHandler,
|
|
||||||
EmptyCredentialsExtractor,
|
|
||||||
MethodPermissionsExtractor,
|
|
||||||
RdfToQuadConverter,
|
|
||||||
QuadToRdfConverter,
|
|
||||||
WaterfallHandler,
|
|
||||||
} from '../../src/index';
|
|
||||||
import type { ServerConfig } from './ServerConfig';
|
|
||||||
import {
|
|
||||||
getInMemoryResourceStore,
|
|
||||||
getConvertingStore,
|
|
||||||
getBasicRequestParser,
|
|
||||||
getOperationHandler,
|
|
||||||
getWebAclAuthorizer,
|
|
||||||
getResponseWriter,
|
|
||||||
} from './Util';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BasicHandlersWithAclConfig works with
|
|
||||||
* - an WebAclAuthorizer
|
|
||||||
* - an InMemoryResourceStore wrapped in a converting store & wrapped in a patching store
|
|
||||||
* - GET, POST, PUT, PATCH & DELETE operation handlers
|
|
||||||
*/
|
|
||||||
|
|
||||||
export class BasicHandlersWithAclConfig implements ServerConfig {
|
|
||||||
public store: ResourceStore;
|
|
||||||
|
|
||||||
public constructor() {
|
|
||||||
this.store = getConvertingStore(
|
|
||||||
getInMemoryResourceStore(),
|
|
||||||
[ new QuadToRdfConverter(),
|
|
||||||
new RdfToQuadConverter() ],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getHttpHandler(): HttpHandler {
|
|
||||||
const requestParser = getBasicRequestParser();
|
|
||||||
|
|
||||||
const credentialsExtractor = new EmptyCredentialsExtractor();
|
|
||||||
const permissionsExtractor = new WaterfallHandler([
|
|
||||||
new MethodPermissionsExtractor(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const operationHandler = getOperationHandler(this.store);
|
|
||||||
|
|
||||||
const responseWriter = getResponseWriter();
|
|
||||||
const authorizer = getWebAclAuthorizer(this.store);
|
|
||||||
|
|
||||||
const handler = new AuthenticatedLdpHandler({
|
|
||||||
requestParser,
|
|
||||||
credentialsExtractor,
|
|
||||||
permissionsExtractor,
|
|
||||||
authorizer,
|
|
||||||
operationHandler,
|
|
||||||
responseWriter,
|
|
||||||
});
|
|
||||||
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,7 +24,6 @@ import {
|
|||||||
ErrorResponseWriter,
|
ErrorResponseWriter,
|
||||||
GetOperationHandler,
|
GetOperationHandler,
|
||||||
HeadOperationHandler,
|
HeadOperationHandler,
|
||||||
InMemoryDataAccessor,
|
|
||||||
LinkRelMetadataWriter,
|
LinkRelMetadataWriter,
|
||||||
LinkTypeParser,
|
LinkTypeParser,
|
||||||
MappedMetadataWriter,
|
MappedMetadataWriter,
|
||||||
@ -63,15 +62,6 @@ export const getRootFilePath = (subfolder: string): string => join(__dirname, '.
|
|||||||
export const getDataAccessorStore = (base: string, dataAccessor: DataAccessor): DataAccessorBasedStore =>
|
export const getDataAccessorStore = (base: string, dataAccessor: DataAccessor): DataAccessorBasedStore =>
|
||||||
new DataAccessorBasedStore(dataAccessor, new SingleRootIdentifierStrategy(base));
|
new DataAccessorBasedStore(dataAccessor, new SingleRootIdentifierStrategy(base));
|
||||||
|
|
||||||
/**
|
|
||||||
* Gives an in memory resource store based on (default) base url.
|
|
||||||
* @param base - Optional base parameter for the run time config.
|
|
||||||
*
|
|
||||||
* @returns The in memory resource store.
|
|
||||||
*/
|
|
||||||
export const getInMemoryResourceStore = (base = BASE): DataAccessorBasedStore =>
|
|
||||||
getDataAccessorStore(base, new InMemoryDataAccessor(BASE));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives a converting store given some converters.
|
* Gives a converting store given some converters.
|
||||||
* @param store - Initial store.
|
* @param store - Initial store.
|
||||||
|
45
test/configs/auth-ldp-handler.json
Normal file
45
test/configs/auth-ldp-handler.json
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^1.0.0/components/context.jsonld",
|
||||||
|
"import": [
|
||||||
|
"files-scs:config/presets/acl.json",
|
||||||
|
"files-scs:config/presets/init.json",
|
||||||
|
"files-scs:config/presets/ldp.json",
|
||||||
|
"files-scs:config/presets/ldp/credentials-extractor.json",
|
||||||
|
"files-scs:config/presets/ldp/metadata-handler.json",
|
||||||
|
"files-scs:config/presets/ldp/operation-handler.json",
|
||||||
|
"files-scs:config/presets/ldp/permissions-extractor.json",
|
||||||
|
"files-scs:config/presets/ldp/response-writer.json",
|
||||||
|
"files-scs:config/presets/ldp/request-parser.json",
|
||||||
|
"files-scs:config/presets/representation-conversion.json",
|
||||||
|
"files-scs:config/presets/storage/backend/storage-memory.json",
|
||||||
|
"files-scs:config/presets/storage-wrapper.json",
|
||||||
|
"files-scs:config/presets/cli-params.json"
|
||||||
|
],
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"@id": "urn:solid-server:test:Instances",
|
||||||
|
"@type": "RecordObject",
|
||||||
|
"RecordObject:_record": [
|
||||||
|
{
|
||||||
|
"RecordObject:_record_key": "initializer",
|
||||||
|
"RecordObject:_record_value": { "@id": "urn:solid-server:default:AclInitializer" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"RecordObject:_record_key": "handler",
|
||||||
|
"RecordObject:_record_value": { "@id": "urn:solid-server:default:LdpHandler" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"RecordObject:_record_key": "store",
|
||||||
|
"RecordObject:_record_value": { "@id": "urn:solid-server:default:ResourceStore" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "urn:solid-server:default:RoutingResourceStore",
|
||||||
|
"@type": "PassthroughStore",
|
||||||
|
"PassthroughStore:_source": {
|
||||||
|
"@id": "urn:solid-server:default:MemoryResourceStore"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,20 +1,23 @@
|
|||||||
import type { MockResponse } from 'node-mocks-http';
|
import type { MockResponse } from 'node-mocks-http';
|
||||||
import { RootContainerInitializer } from '../../src/init/RootContainerInitializer';
|
import type { HttpHandler, Initializer, ResourceStore } from '../../src/';
|
||||||
import { BasicHandlersWithAclConfig } from '../configs/BasicHandlersWithAclConfig';
|
import { BASE, instantiateFromConfig } from '../configs/Util';
|
||||||
import { BASE } from '../configs/Util';
|
|
||||||
import { AclTestHelper } from '../util/TestHelpers';
|
import { AclTestHelper } from '../util/TestHelpers';
|
||||||
import { call } from '../util/Util';
|
import { call } from '../util/Util';
|
||||||
|
|
||||||
describe('A server with authorization', (): void => {
|
describe('A server with authorization', (): void => {
|
||||||
const config = new BasicHandlersWithAclConfig();
|
let handler: HttpHandler;
|
||||||
const handler = config.getHttpHandler();
|
let aclHelper: AclTestHelper;
|
||||||
const { store } = config;
|
|
||||||
const aclHelper = new AclTestHelper(store, 'http://test.com/');
|
|
||||||
|
|
||||||
beforeAll(async(): Promise<void> => {
|
beforeAll(async(): Promise<void> => {
|
||||||
// Initialize store
|
let initializer: Initializer,
|
||||||
const initializer = new RootContainerInitializer(BASE, config.store);
|
store: ResourceStore;
|
||||||
|
const instances = await instantiateFromConfig('urn:solid-server:test:Instances', 'auth-ldp-handler.json', {
|
||||||
|
'urn:solid-server:default:variable:baseUrl': BASE,
|
||||||
|
}) as Record<string, any>;
|
||||||
|
({ handler, store, initializer } = instances);
|
||||||
|
|
||||||
await initializer.handleSafe();
|
await initializer.handleSafe();
|
||||||
|
aclHelper = new AclTestHelper(store, BASE);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can create new entries.', async(): Promise<void> => {
|
it('can create new entries.', async(): Promise<void> => {
|
||||||
|
@ -6,8 +6,8 @@ import { Readable } from 'stream';
|
|||||||
import * as url from 'url';
|
import * as url from 'url';
|
||||||
import type { MockResponse } from 'node-mocks-http';
|
import type { MockResponse } from 'node-mocks-http';
|
||||||
import { createResponse } from 'node-mocks-http';
|
import { createResponse } from 'node-mocks-http';
|
||||||
import type { ResourceStore, PermissionSet, HttpHandler, HttpRequest } from '../../src/index';
|
import type { ResourceStore, PermissionSet, HttpHandler, HttpRequest } from '../../src/';
|
||||||
import { guardedStreamFrom, RepresentationMetadata } from '../../src/index';
|
import { guardedStreamFrom, RepresentationMetadata, ensureTrailingSlash } from '../../src/';
|
||||||
import { CONTENT_TYPE } from '../../src/util/UriConstants';
|
import { CONTENT_TYPE } from '../../src/util/UriConstants';
|
||||||
import { call } from './Util';
|
import { call } from './Util';
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ export class AclTestHelper {
|
|||||||
|
|
||||||
public constructor(store: ResourceStore, id: string) {
|
public constructor(store: ResourceStore, id: string) {
|
||||||
this.store = store;
|
this.store = store;
|
||||||
this.id = id;
|
this.id = ensureTrailingSlash(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setSimpleAcl(
|
public async setSimpleAcl(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user