Merge pull request #22675 from backstage/rugvip/auth-exp-tweaks
auth-backend: completely remove hardcoded session expiration
This commit is contained in:
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user