updates scope configuration

Signed-off-by: Daniel Deloff <44780793+rv-ddeloff@users.noreply.github.com>
This commit is contained in:
Daniel Deloff
2021-10-11 16:45:50 -04:00
parent 037447efd3
commit 5cb4d2eabc
4 changed files with 99 additions and 32 deletions
+5
View File
@@ -364,6 +364,11 @@ auth:
development:
clientId: ${AUTH_BITBUCKET_CLIENT_ID}
clientSecret: ${AUTH_BITBUCKET_CLIENT_SECRET}
atlassian:
development:
clientId: ${AUTH_ATLASSIAN_CLIENT_ID}
clientSecret: ${AUTH_ATLASSIAN_CLIENT_SECRET}
scopes: ${AUTH_ATLASSIAN_SCOPES}
costInsights:
engineerCost: 200000
products:
@@ -14,12 +14,16 @@
* limitations under the License.
*/
import { AtlassianAuthProvider } from './provider';
import {
AtlassianAuthProvider,
atlassianDefaultSignInResolver,
} from './provider';
import * as helpers from '../../lib/passport/PassportStrategyHelper';
import { getVoidLogger } from '@backstage/backend-common';
import { TokenIssuer } from '../../identity';
import { CatalogIdentityClient } from '../../lib/catalog';
import { OAuthResult } from '../../lib/oauth';
import { PassportProfile } from '../../lib/passport/types';
const mockFrameHandler = jest.spyOn(
helpers,
@@ -27,33 +31,34 @@ const mockFrameHandler = jest.spyOn(
) as unknown as jest.MockedFunction<() => Promise<{ result: OAuthResult }>>;
describe('createAtlassianProvider', () => {
const tokenIssuer = {
issueToken: jest.fn(),
listPublicKeys: jest.fn(),
};
const catalogIdentityClient = {
findUser: jest.fn(),
};
const provider = new AtlassianAuthProvider({
logger: getVoidLogger(),
catalogIdentityClient:
catalogIdentityClient as unknown as CatalogIdentityClient,
tokenIssuer: tokenIssuer as unknown as TokenIssuer,
authHandler: async ({ fullProfile }) => ({
profile: {
email: fullProfile.emails![0]!.value,
displayName: fullProfile.displayName,
picture: 'http://google.com/lols',
},
}),
clientId: 'mock',
clientSecret: 'mock',
callbackUrl: 'mock',
scopes: [],
signInResolver: atlassianDefaultSignInResolver,
});
it('should auth', async () => {
const tokenIssuer = {
issueToken: jest.fn(),
listPublicKeys: jest.fn(),
};
const catalogIdentityClient = {
findUser: jest.fn(),
};
const provider = new AtlassianAuthProvider({
logger: getVoidLogger(),
catalogIdentityClient:
catalogIdentityClient as unknown as CatalogIdentityClient,
tokenIssuer: tokenIssuer as unknown as TokenIssuer,
authHandler: async ({ fullProfile }) => ({
profile: {
email: fullProfile.emails![0]!.value,
displayName: fullProfile.displayName,
picture: 'http://google.com/lols',
},
}),
clientId: 'mock',
clientSecret: 'mock',
callbackUrl: 'mock',
scopes: [],
});
mockFrameHandler.mockResolvedValueOnce({
result: {
fullProfile: {
@@ -79,6 +84,9 @@ describe('createAtlassianProvider', () => {
});
const { response } = await provider.handler({} as any);
expect(response).toEqual({
backstageIdentity: {
id: 'conrad',
},
providerInfo: {
accessToken: 'accessToken',
expiresInSeconds: 123,
@@ -93,4 +101,56 @@ describe('createAtlassianProvider', () => {
},
});
});
it('should forward a new refresh token on refresh', async () => {
const mockRefreshToken = jest.spyOn(
helpers,
'executeRefreshTokenStrategy',
) as unknown as jest.MockedFunction<() => Promise<{}>>;
mockRefreshToken.mockResolvedValueOnce({
accessToken: 'a.b.c',
refreshToken: 'dont-forget-to-send-refresh',
params: {
id_token: 'my-id',
scope: 'read_user',
},
});
const mockUserProfile = jest.spyOn(
helpers,
'executeFetchUserProfileStrategy',
) as unknown as jest.MockedFunction<() => Promise<PassportProfile>>;
mockUserProfile.mockResolvedValueOnce({
id: 'uid-my-id',
username: 'mockuser',
provider: 'atlassian',
displayName: 'Mocked User',
emails: [
{
value: 'mockuser@gmail.com',
},
],
});
const response = await provider.refresh({} as any);
expect(response).toEqual({
backstageIdentity: {
id: 'mockuser',
},
profile: {
displayName: 'Mocked User',
email: 'mockuser@gmail.com',
picture: 'http://google.com/lols',
},
providerInfo: {
accessToken: 'a.b.c',
idToken: 'my-id',
refreshToken: 'dont-forget-to-send-refresh',
scope: 'read_user',
},
});
});
});
@@ -145,7 +145,7 @@ export class AtlassianAuthProvider implements OAuthHandlers {
providerInfo: {
idToken: result.params.id_token,
accessToken: result.accessToken,
refreshToken: result.refreshToken, // GitLab expires the old refresh token when used
refreshToken: result.refreshToken,
scope: result.params.scope,
expiresInSeconds: result.params.expires_in,
},
@@ -229,7 +229,7 @@ export const createAtlassianProvider = (
OAuthEnvironmentHandler.mapConfig(config, envConfig => {
const clientId = envConfig.getString('clientId');
const clientSecret = envConfig.getString('clientSecret');
const scopes = envConfig.getStringArray('scopes');
const scopes = envConfig.getString('scopes');
const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
const catalogIdentityClient = new CatalogIdentityClient({
@@ -253,7 +253,7 @@ export const createAtlassianProvider = (
const provider = new AtlassianAuthProvider({
clientId,
clientSecret,
scopes,
scopes: [scopes],
callbackUrl,
authHandler,
signInResolver,
@@ -29,7 +29,7 @@ interface AtlassianStrategyOptions {
clientID: string;
clientSecret: string;
callbackURL: string;
scope: string[];
scope: string;
}
const defaultScopes = ['offline_access', 'read:me'];
@@ -45,11 +45,13 @@ export default class AtlassianStrategy extends OAuth2Strategy {
throw new TypeError('Atlassian requires a scope option');
}
const scopes = options.scope.split(' ');
const optionsWithURLs = {
...options,
authorizationURL: `https://auth.atlassian.com/authorize`,
tokenURL: `https://auth.atlassian.com/oauth/token`,
scope: Array.from(new Set([...defaultScopes, ...options.scope])),
scope: Array.from(new Set([...defaultScopes, ...scopes])),
};
super(optionsWithURLs, verify);