feat: Let CredentialsExtractors specify what type of Credentials they generate

This commit is contained in:
Joachim Van Herwegen
2021-09-17 11:17:43 +02:00
parent 34a44d1636
commit c3fa74de78
21 changed files with 115 additions and 81 deletions

View File

@@ -4,12 +4,10 @@ import { getLoggerFor } from '../logging/LogUtil';
import type { HttpRequest } from '../server/HttpRequest';
import { BadRequestHttpError } from '../util/errors/BadRequestHttpError';
import { NotImplementedHttpError } from '../util/errors/NotImplementedHttpError';
import type { Credentials } from './Credentials';
import { CredentialGroup } from './Credentials';
import type { CredentialSet } from './Credentials';
import { CredentialsExtractor } from './CredentialsExtractor';
/**
* Credentials extractor that extracts a WebID from a Bearer access token.
*/
export class BearerWebIdExtractor extends CredentialsExtractor {
protected readonly logger = getLoggerFor(this);
private readonly verify: SolidTokenVerifierFunction;
@@ -26,13 +24,13 @@ export class BearerWebIdExtractor extends CredentialsExtractor {
}
}
public async handle(request: HttpRequest): Promise<Credentials> {
public async handle(request: HttpRequest): Promise<CredentialSet> {
const { headers: { authorization }} = request;
try {
const { webid: webId } = await this.verify(authorization!);
this.logger.info(`Verified WebID via Bearer access token: ${webId}`);
return { webId };
return { [CredentialGroup.agent]: { webId }};
} catch (error: unknown) {
const message = `Error verifying WebID via Bearer access token: ${(error as Error).message}`;
this.logger.warn(message);

View File

@@ -1,6 +1,19 @@
/**
* Credentials identifying an entity accessing or owning data.
*/
export interface Credentials {
export interface Credential {
webId?: string;
}
/**
* Specific groups that can have credentials.
*/
export enum CredentialGroup {
public = 'public',
agent = 'agent',
}
/**
* A combination of multiple credentials, where their group is specified by the key.
*/
export type CredentialSet = Partial<Record<CredentialGroup, Credential>>;

View File

@@ -1,8 +1,8 @@
import type { HttpRequest } from '../server/HttpRequest';
import { AsyncHandler } from '../util/handlers/AsyncHandler';
import type { Credentials } from './Credentials';
import type { CredentialSet } from './Credentials';
/**
* Responsible for extracting credentials from an incoming request.
*/
export abstract class CredentialsExtractor extends AsyncHandler<HttpRequest, Credentials> {}
export abstract class CredentialsExtractor extends AsyncHandler<HttpRequest, CredentialSet> {}

View File

@@ -5,7 +5,8 @@ import { getLoggerFor } from '../logging/LogUtil';
import type { HttpRequest } from '../server/HttpRequest';
import { BadRequestHttpError } from '../util/errors/BadRequestHttpError';
import { NotImplementedHttpError } from '../util/errors/NotImplementedHttpError';
import type { Credentials } from './Credentials';
import { CredentialGroup } from './Credentials';
import type { CredentialSet } from './Credentials';
import { CredentialsExtractor } from './CredentialsExtractor';
/**
@@ -31,7 +32,7 @@ export class DPoPWebIdExtractor extends CredentialsExtractor {
}
}
public async handle(request: HttpRequest): Promise<Credentials> {
public async handle(request: HttpRequest): Promise<CredentialSet> {
const { headers: { authorization, dpop }, method } = request;
if (!dpop) {
throw new BadRequestHttpError('No DPoP header specified.');
@@ -53,7 +54,7 @@ export class DPoPWebIdExtractor extends CredentialsExtractor {
},
);
this.logger.info(`Verified WebID via DPoP-bound access token: ${webId}`);
return { webId };
return { [CredentialGroup.agent]: { webId }};
} catch (error: unknown) {
const message = `Error verifying WebID via DPoP-bound access token: ${(error as Error).message}`;
this.logger.warn(message);

View File

@@ -1,6 +1,7 @@
import type { HttpRequest } from '../server/HttpRequest';
import { NotImplementedHttpError } from '../util/errors/NotImplementedHttpError';
import type { Credentials } from './Credentials';
import { CredentialGroup } from './Credentials';
import type { CredentialSet } from './Credentials';
import { CredentialsExtractor } from './CredentialsExtractor';
/**
@@ -14,7 +15,7 @@ export class EmptyCredentialsExtractor extends CredentialsExtractor {
}
}
public async handle(): Promise<Credentials> {
return {};
public async handle(): Promise<CredentialSet> {
return { [CredentialGroup.public]: {}};
}
}

View File

@@ -1,5 +1,6 @@
import { getLoggerFor } from '../logging/LogUtil';
import type { Credentials } from './Credentials';
import { CredentialGroup } from './Credentials';
import type { Credential, CredentialSet } from './Credentials';
import { CredentialsExtractor } from './CredentialsExtractor';
/**
@@ -7,18 +8,18 @@ import { CredentialsExtractor } from './CredentialsExtractor';
* (useful for development or debugging purposes).
*/
export class UnsecureConstantCredentialsExtractor extends CredentialsExtractor {
private readonly agent: Credentials;
private readonly credentials: CredentialSet;
private readonly logger = getLoggerFor(this);
public constructor(agent: string);
public constructor(agent: Credentials);
public constructor(agent: string | Credentials) {
public constructor(agent: Credential);
public constructor(agent: string | Credential) {
super();
this.agent = typeof agent === 'string' ? { webId: agent } : agent;
this.credentials = { [CredentialGroup.agent]: typeof agent === 'string' ? { webId: agent } : agent };
}
public async handle(): Promise<Credentials> {
this.logger.info(`Agent unsecurely claims to be ${this.agent.webId}`);
return this.agent;
public async handle(): Promise<CredentialSet> {
this.logger.info(`Agent unsecurely claims to be ${this.credentials.agent!.webId}`);
return this.credentials;
}
}

View File

@@ -1,7 +1,8 @@
import { getLoggerFor } from '../logging/LogUtil';
import type { HttpRequest } from '../server/HttpRequest';
import { NotImplementedHttpError } from '../util/errors/NotImplementedHttpError';
import type { Credentials } from './Credentials';
import { CredentialGroup } from './Credentials';
import type { CredentialSet } from './Credentials';
import { CredentialsExtractor } from './CredentialsExtractor';
/**
@@ -17,9 +18,9 @@ export class UnsecureWebIdExtractor extends CredentialsExtractor {
}
}
public async handle({ headers }: HttpRequest): Promise<Credentials> {
public async handle({ headers }: HttpRequest): Promise<CredentialSet> {
const webId = /^WebID\s+(.*)/u.exec(headers.authorization!)![1];
this.logger.info(`Agent unsecurely claims to be ${webId}`);
return { webId };
return { [CredentialGroup.agent]: { webId }};
}
}