auth-backend: refactor to remove internal hardcoded default session expiration

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-02-03 12:34:06 +01:00
parent de1aa5179c
commit 87dea686bf
6 changed files with 125 additions and 130 deletions
@@ -1,19 +0,0 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// BACKSTAGE_SESSION_EXPIRATION the default session expiration time
// TODO: find a less hard-coded way to access this, perhaps by reading it from the configuration.
export const BACKSTAGE_SESSION_EXPIRATION = 3600;
@@ -1,17 +0,0 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { BACKSTAGE_SESSION_EXPIRATION } from './constants';
@@ -0,0 +1,77 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ConfigReader } from '@backstage/config';
import { readBackstageTokenExpiration } from './readBackstageTokenExpiration';
describe('Test for default backstage token expiry time', () => {
it('Will return default backstage session expiration', () => {
const config = new ConfigReader({
app: {
baseUrl: 'http://example.com/extra-path',
},
});
expect(readBackstageTokenExpiration(config)).toBe(3600);
});
it('Will return user defined 120 minutes as backstage session expiration', () => {
const config = new ConfigReader({
app: {
baseUrl: 'http://example.com/extra-path',
},
auth: {
backstageTokenExpiration: { minutes: 120 },
},
});
expect(readBackstageTokenExpiration(config)).toBe(7200);
});
it('Will return minimum duration of 10 minutes as backstage session expiration', () => {
const config = new ConfigReader({
app: {
baseUrl: 'http://example.com/extra-path',
},
auth: {
backstageTokenExpiration: { minutes: 2 },
},
});
expect(readBackstageTokenExpiration(config)).toBe(600);
});
it('Will return user configured value as backstage session expiration', () => {
const config = new ConfigReader({
app: {
baseUrl: 'http://example.com/extra-path',
},
auth: {
backstageTokenExpiration: { minutes: 20 },
},
});
expect(readBackstageTokenExpiration(config)).toBe(1200);
});
it('Will return maximum of 24 hour as backstage session expiration if user configured value is more than a day', () => {
const config = new ConfigReader({
app: {
baseUrl: 'http://example.com/extra-path',
},
auth: {
backstageTokenExpiration: { minutes: 1500 },
},
});
expect(readBackstageTokenExpiration(config)).toBe(86400);
});
});
@@ -0,0 +1,44 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { RootConfigService } from '@backstage/backend-plugin-api';
import { readDurationFromConfig } from '@backstage/config';
import { durationToMilliseconds } from '@backstage/types';
const TOKEN_EXP_DEFAULT_S = 3600;
const TOKEN_EXP_MIN_S = 600;
const TOKEN_EXP_MAX_S = 86400;
export function readBackstageTokenExpiration(config: RootConfigService) {
const processingIntervalKey = 'auth.backstageTokenExpiration';
if (!config.has(processingIntervalKey)) {
return TOKEN_EXP_DEFAULT_S;
}
const duration = readDurationFromConfig(config, {
key: processingIntervalKey,
});
const durationS = Math.round(durationToMilliseconds(duration) / 1000);
if (durationS < TOKEN_EXP_MIN_S) {
return TOKEN_EXP_MIN_S;
} else if (durationS > TOKEN_EXP_MAX_S) {
return TOKEN_EXP_MAX_S;
}
return durationS;
}
@@ -15,11 +15,7 @@
*/
import { ConfigReader } from '@backstage/config';
import {
createOriginFilter,
getDefaultBackstageTokenExpiryTime,
} from './router';
import { BACKSTAGE_SESSION_EXPIRATION } from '../lib/session';
import { createOriginFilter } from './router';
describe('Auth origin filtering', () => {
const config = new ConfigReader({
@@ -56,64 +52,3 @@ describe('Auth origin filtering', () => {
expect(createOriginFilter(config)(origin)).toBeTruthy();
});
});
describe('Test for default backstage token expiry time', () => {
it('Will return default backstage session expiration', () => {
const config = new ConfigReader({
app: {
baseUrl: 'http://example.com/extra-path',
},
});
expect(getDefaultBackstageTokenExpiryTime(config)).toBe(
BACKSTAGE_SESSION_EXPIRATION,
);
});
it('Will return user defined 120 minutes as backstage session expiration', () => {
const config = new ConfigReader({
app: {
baseUrl: 'http://example.com/extra-path',
},
auth: {
backstageTokenExpiration: { minutes: 120 },
},
});
expect(getDefaultBackstageTokenExpiryTime(config)).toBe(7200);
});
it('Will return minimum duration of 10 minutes as backstage session expiration', () => {
const config = new ConfigReader({
app: {
baseUrl: 'http://example.com/extra-path',
},
auth: {
backstageTokenExpiration: { minutes: 2 },
},
});
expect(getDefaultBackstageTokenExpiryTime(config)).toBe(600);
});
it('Will return user configured value as backstage session expiration', () => {
const config = new ConfigReader({
app: {
baseUrl: 'http://example.com/extra-path',
},
auth: {
backstageTokenExpiration: { minutes: 20 },
},
});
expect(getDefaultBackstageTokenExpiryTime(config)).toBe(1200);
});
it('Will return maximum of 24 hour as backstage session expiration if user configured value is more than a day', () => {
const config = new ConfigReader({
app: {
baseUrl: 'http://example.com/extra-path',
},
auth: {
backstageTokenExpiration: { minutes: 1500 },
},
});
expect(getDefaultBackstageTokenExpiryTime(config)).toBe(86400);
});
});
+3 -28
View File
@@ -36,12 +36,11 @@ import passport from 'passport';
import { Minimatch } from 'minimatch';
import { CatalogAuthResolverContext } from '../lib/resolvers';
import { AuthDatabase } from '../database/AuthDatabase';
import { BACKSTAGE_SESSION_EXPIRATION } from '../lib/session';
import { readBackstageTokenExpiration } from './readBackstageTokenExpiration';
import { TokenIssuer } from '../identity/types';
import { StaticTokenIssuer } from '../identity/StaticTokenIssuer';
import { StaticKeyStore } from '../identity/StaticKeyStore';
import { Config, readDurationFromConfig } from '@backstage/config';
import { durationToMilliseconds } from '@backstage/types';
import { Config } from '@backstage/config';
/** @public */
export type ProviderFactories = { [s: string]: AuthProviderFactory };
@@ -77,7 +76,7 @@ export async function createRouter(
const appUrl = config.getString('app.baseUrl');
const authUrl = await discovery.getExternalBaseUrl('auth');
const backstageTokenExpiration = getDefaultBackstageTokenExpiryTime(config);
const backstageTokenExpiration = readBackstageTokenExpiration(config);
const authDb = AuthDatabase.create(database);
const keyStore = await KeyStores.fromConfig(config, {
@@ -249,27 +248,3 @@ export function createOriginFilter(
return allowedOriginPatterns.some(pattern => pattern.match(origin));
};
}
/** @internal */
export function getDefaultBackstageTokenExpiryTime(config: Config) {
const processingIntervalKey = 'auth.backstageTokenExpiration';
if (!config.has(processingIntervalKey)) {
return BACKSTAGE_SESSION_EXPIRATION;
}
const duration = readDurationFromConfig(config, {
key: processingIntervalKey,
});
const roundedDuration = Math.round(durationToMilliseconds(duration) / 1000);
const minSeconds = Math.max(600, roundedDuration);
const maxSeconds = Math.min(86400, roundedDuration);
if (roundedDuration < minSeconds) {
return minSeconds
}
return maxSeconds;
}