auth-backend: remove disableRefresh option

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2022-05-12 14:51:19 +02:00
parent 57673ce1b9
commit 2df2f01a29
15 changed files with 22 additions and 75 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': patch
---
The Auth0 adapter no longer disables session refreshing.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': minor
---
Removed the explicit `disableRefresh` option from `OAuthAdapter`. Refresh can still be disabled for a provider by not implementing the `refresh` method.
-1
View File
@@ -153,7 +153,6 @@ export const createOktaProvider: AuthProviderFactory = ({
// Wrap the OAuthProviderHandlers with OAuthProvider, which implements AuthProviderRouteHandlers
return OAuthProvider.fromConfig(globalConfig, provider, {
disableRefresh: false,
providerId,
tokenIssuer,
});
+1 -5
View File
@@ -586,11 +586,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
handlers: OAuthHandlers,
options: Pick<
Options,
| 'providerId'
| 'persistScopes'
| 'disableRefresh'
| 'tokenIssuer'
| 'callbackUrl'
'providerId' | 'persistScopes' | 'tokenIssuer' | 'callbackUrl'
>,
): OAuthAdapter;
// (undocumented)
@@ -60,7 +60,6 @@ describe('OAuthAdapter', () => {
const oAuthProviderOptions = {
providerId: 'test-provider',
secure: false,
disableRefresh: true,
appOrigin: 'http://localhost:3000',
cookieDomain: 'example.com',
cookiePath: '/auth/test-provider',
@@ -110,7 +109,6 @@ describe('OAuthAdapter', () => {
it('sets the refresh cookie if refresh is enabled', async () => {
const oauthProvider = new OAuthAdapter(providerInstance, {
...oAuthProviderOptions,
disableRefresh: false,
isOriginAllowed: () => false,
});
@@ -153,7 +151,6 @@ describe('OAuthAdapter', () => {
};
const oauthProvider = new OAuthAdapter(handlers, {
...oAuthProviderOptions,
disableRefresh: false,
persistScopes: true,
});
@@ -238,36 +235,9 @@ describe('OAuthAdapter', () => {
);
});
it('does not set the refresh cookie if refresh is disabled', async () => {
const oauthProvider = new OAuthAdapter(providerInstance, {
...oAuthProviderOptions,
disableRefresh: true,
isOriginAllowed: () => false,
});
const mockRequest = {
cookies: {
'test-provider-nonce': 'nonce',
},
query: {
state: 'nonce',
},
} as unknown as express.Request;
const mockResponse = {
cookie: jest.fn().mockReturnThis(),
setHeader: jest.fn().mockReturnThis(),
end: jest.fn().mockReturnThis(),
} as unknown as express.Response;
await oauthProvider.frameHandler(mockRequest, mockResponse);
expect(mockResponse.cookie).toHaveBeenCalledTimes(0);
});
it('removes refresh cookie when logging out', async () => {
const oauthProvider = new OAuthAdapter(providerInstance, {
...oAuthProviderOptions,
disableRefresh: false,
isOriginAllowed: () => false,
});
@@ -292,10 +262,8 @@ describe('OAuthAdapter', () => {
});
it('gets new access-token when refreshing', async () => {
oAuthProviderOptions.disableRefresh = false;
const oauthProvider = new OAuthAdapter(providerInstance, {
...oAuthProviderOptions,
disableRefresh: false,
isOriginAllowed: () => false,
});
@@ -327,26 +295,6 @@ describe('OAuthAdapter', () => {
});
});
it('handles refresh without capabilities', async () => {
const oauthProvider = new OAuthAdapter(providerInstance, {
...oAuthProviderOptions,
disableRefresh: true,
isOriginAllowed: () => false,
});
const mockRequest = {
header: () => 'XMLHttpRequest',
} as unknown as express.Request;
const mockResponse = {} as unknown as express.Response;
await expect(
oauthProvider.refresh(mockRequest, mockResponse),
).rejects.toThrow(
'Refresh token is not supported for provider test-provider',
);
});
it('sets the correct cookie configuration using a callbackUrl', async () => {
const config = {
baseUrl: 'http://domain.org/auth',
@@ -48,7 +48,6 @@ export const TEN_MINUTES_MS = 600 * 1000;
export type Options = {
providerId: string;
secure: boolean;
disableRefresh?: boolean;
persistScopes?: boolean;
cookieDomain: string;
cookiePath: string;
@@ -64,11 +63,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
handlers: OAuthHandlers,
options: Pick<
Options,
| 'providerId'
| 'persistScopes'
| 'disableRefresh'
| 'tokenIssuer'
| 'callbackUrl'
'providerId' | 'persistScopes' | 'tokenIssuer' | 'callbackUrl'
>,
): OAuthAdapter {
const { origin: appOrigin } = new URL(config.appUrl);
@@ -170,7 +165,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
response.providerInfo.scope = state.scope;
}
if (refreshToken && !this.options.disableRefresh) {
if (refreshToken) {
// set new refresh token
this.setRefreshTokenCookie(res, refreshToken);
}
@@ -210,7 +205,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
throw new AuthenticationError('Invalid X-Requested-With header');
}
if (!this.handlers.refresh || this.options.disableRefresh) {
if (!this.handlers.refresh) {
throw new InputError(
`Refresh token is not supported for provider ${this.options.providerId}`,
);
@@ -243,7 +243,6 @@ export const auth0 = createAuthProviderIntegration({
});
return OAuthAdapter.fromConfig(globalConfig, provider, {
disableRefresh: true,
providerId,
callbackUrl,
});
@@ -261,7 +261,6 @@ export const bitbucket = createAuthProviderIntegration({
});
return OAuthAdapter.fromConfig(globalConfig, provider, {
disableRefresh: false,
providerId,
callbackUrl,
});
@@ -248,7 +248,6 @@ export const gitlab = createAuthProviderIntegration({
});
return OAuthAdapter.fromConfig(globalConfig, provider, {
disableRefresh: false,
providerId,
callbackUrl,
});
@@ -238,7 +238,6 @@ export const google = createAuthProviderIntegration({
});
return OAuthAdapter.fromConfig(globalConfig, provider, {
disableRefresh: false,
providerId,
callbackUrl,
});
@@ -267,7 +267,6 @@ export const microsoft = createAuthProviderIntegration({
});
return OAuthAdapter.fromConfig(globalConfig, provider, {
disableRefresh: false,
providerId,
callbackUrl,
});
@@ -43,6 +43,7 @@ import {
SignInResolver,
} from '../types';
import { createAuthProviderIntegration } from '../createAuthProviderIntegration';
import { InputError } from '@backstage/errors';
type PrivateInfo = {
refreshToken: string;
@@ -56,6 +57,7 @@ export type OAuth2AuthProviderOptions = OAuthProviderOptions & {
scope?: string;
resolverContext: AuthResolverContext;
includeBasicAuth?: boolean;
disableRefresh?: boolean;
};
export class OAuth2AuthProvider implements OAuthHandlers {
@@ -63,11 +65,13 @@ export class OAuth2AuthProvider implements OAuthHandlers {
private readonly signInResolver?: SignInResolver<OAuthResult>;
private readonly authHandler: AuthHandler<OAuthResult>;
private readonly resolverContext: AuthResolverContext;
private readonly disableRefresh: boolean;
constructor(options: OAuth2AuthProviderOptions) {
this.signInResolver = options.signInResolver;
this.authHandler = options.authHandler;
this.resolverContext = options.resolverContext;
this.disableRefresh = options.disableRefresh ?? false;
this._strategy = new OAuth2Strategy(
{
@@ -132,6 +136,9 @@ export class OAuth2AuthProvider implements OAuthHandlers {
}
async refresh(req: OAuthRefreshRequest) {
if (this.disableRefresh) {
throw new InputError('Session refreshes have been disabled');
}
const refreshTokenResponse = await executeRefreshTokenStrategy(
this._strategy,
req.refreshToken,
@@ -243,10 +250,10 @@ export const oauth2 = createAuthProviderIntegration({
scope,
includeBasicAuth,
resolverContext,
disableRefresh,
});
return OAuthAdapter.fromConfig(globalConfig, provider, {
disableRefresh,
providerId,
callbackUrl,
});
@@ -262,7 +262,6 @@ export const oidc = createAuthProviderIntegration({
});
return OAuthAdapter.fromConfig(globalConfig, provider, {
disableRefresh: false,
providerId,
callbackUrl,
});
@@ -271,7 +271,6 @@ export const okta = createAuthProviderIntegration({
});
return OAuthAdapter.fromConfig(globalConfig, provider, {
disableRefresh: false,
providerId,
callbackUrl,
});
@@ -238,7 +238,6 @@ export const onelogin = createAuthProviderIntegration({
});
return OAuthAdapter.fromConfig(globalConfig, provider, {
disableRefresh: false,
providerId,
callbackUrl,
});