backend-common: extract NoopTokenManager from ServerTokenManager
Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { TokenManager } from './types';
|
||||
import { ServerTokenManager } from './ServerTokenManager';
|
||||
|
||||
const emptyConfig = new ConfigReader({});
|
||||
@@ -122,8 +123,40 @@ describe('ServerTokenManager', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('ServerTokenManager.fromConfig', () => {
|
||||
it('should throw if backend auth configuration is missing', () => {
|
||||
expect(() =>
|
||||
ServerTokenManager.fromConfig(new ConfigReader({})),
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
it('should throw if no keys are included in the configuration', () => {
|
||||
expect(() =>
|
||||
ServerTokenManager.fromConfig(
|
||||
new ConfigReader({
|
||||
backend: { auth: { keys: [] } },
|
||||
}),
|
||||
),
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
it('should throw if any key is missing a secret property', () => {
|
||||
expect(() =>
|
||||
ServerTokenManager.fromConfig(
|
||||
new ConfigReader({
|
||||
backend: {
|
||||
auth: {
|
||||
keys: [{ secret: '123' }, {}, { secret: '789' }],
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ServerTokenManager.noop', () => {
|
||||
let noopTokenManager: ServerTokenManager;
|
||||
let noopTokenManager: TokenManager;
|
||||
|
||||
beforeEach(() => {
|
||||
noopTokenManager = ServerTokenManager.noop();
|
||||
@@ -146,11 +179,11 @@ describe('ServerTokenManager', () => {
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
it('should not accept signed tokens', async () => {
|
||||
it('should accept signed tokens', async () => {
|
||||
const tokenManager = ServerTokenManager.fromConfig(configWithSecret);
|
||||
await expect(
|
||||
noopTokenManager.authenticate((await tokenManager.getToken()).token),
|
||||
).rejects.toThrowError(/invalid server token/i);
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,6 +19,14 @@ import { Config } from '@backstage/config';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import { TokenManager } from './types';
|
||||
|
||||
class NoopTokenManager implements TokenManager {
|
||||
async getToken() {
|
||||
return { token: '' };
|
||||
}
|
||||
|
||||
async authenticate() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and validates tokens for use during backend-to-backend
|
||||
* authentication.
|
||||
@@ -26,12 +34,11 @@ import { TokenManager } from './types';
|
||||
* @public
|
||||
*/
|
||||
export class ServerTokenManager implements TokenManager {
|
||||
private readonly verificationKeys: JWKS.KeyStore | JWK.NoneKey;
|
||||
private readonly signingKey: JWK.Key | JWK.NoneKey;
|
||||
private readonly signingAlgorithm: string | undefined;
|
||||
private readonly verificationKeys: JWKS.KeyStore;
|
||||
private readonly signingKey: JWK.Key;
|
||||
|
||||
static noop() {
|
||||
return new ServerTokenManager();
|
||||
return new NoopTokenManager();
|
||||
}
|
||||
|
||||
static fromConfig(config: Config) {
|
||||
@@ -43,20 +50,21 @@ export class ServerTokenManager implements TokenManager {
|
||||
}
|
||||
|
||||
private constructor(secrets?: string[]) {
|
||||
if (secrets?.length) {
|
||||
this.verificationKeys = new JWKS.KeyStore(
|
||||
secrets.map(k => JWK.asKey({ kty: 'oct', k })),
|
||||
if (!secrets?.length) {
|
||||
throw new Error(
|
||||
'No secrets provided when constructing ServerTokenManager',
|
||||
);
|
||||
this.signingKey = this.verificationKeys.all()[0];
|
||||
this.signingAlgorithm = 'HS256';
|
||||
} else {
|
||||
this.verificationKeys = this.signingKey = JWK.None;
|
||||
}
|
||||
|
||||
this.verificationKeys = new JWKS.KeyStore(
|
||||
secrets.map(k => JWK.asKey({ kty: 'oct', k })),
|
||||
);
|
||||
this.signingKey = this.verificationKeys.all()[0];
|
||||
}
|
||||
|
||||
async getToken(): Promise<{ token: string }> {
|
||||
const jwt = JWT.sign({ sub: 'backstage-server' }, this.signingKey, {
|
||||
algorithm: this.signingAlgorithm,
|
||||
algorithm: 'HS256',
|
||||
});
|
||||
|
||||
return { token: jwt };
|
||||
|
||||
Reference in New Issue
Block a user