Fix authorization header for GitLab requests
Signed-off-by: Cptn Fizzbin <code@cptnfizzbin.ca>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/backend-defaults': patch
|
||||
'@backstage/integration': patch
|
||||
---
|
||||
|
||||
UrlReader: Fix handling of access tokens for GitLab readURL requests
|
||||
@@ -108,9 +108,6 @@ describe('GitlabUrlReader', () => {
|
||||
config: createConfig(),
|
||||
response: expect.objectContaining({
|
||||
url: 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch',
|
||||
headers: expect.objectContaining({
|
||||
'private-token': '',
|
||||
}),
|
||||
}),
|
||||
},
|
||||
{
|
||||
@@ -119,7 +116,7 @@ describe('GitlabUrlReader', () => {
|
||||
response: expect.objectContaining({
|
||||
url: 'https://gitlab.example.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch',
|
||||
headers: expect.objectContaining({
|
||||
'private-token': '0123456789',
|
||||
authorization: 'Bearer 0123456789',
|
||||
}),
|
||||
}),
|
||||
},
|
||||
@@ -252,10 +249,10 @@ describe('GitlabUrlReader', () => {
|
||||
it('should return the file when using a user token', async () => {
|
||||
worker.use(
|
||||
rest.get('*/api/v4/projects/user%2Fproject', (req, res, ctx) => {
|
||||
if (req.headers.get('private-token') !== 'gl-user-token') {
|
||||
if (req.headers.get('authorization') !== 'Bearer gl-user-token') {
|
||||
return res(
|
||||
ctx.status(403),
|
||||
ctx.json({ message: 'Not Authorized' }),
|
||||
ctx.status(401),
|
||||
ctx.json({ message: '401 Unauthorized' }),
|
||||
);
|
||||
}
|
||||
return res(ctx.status(200), ctx.json({ id: 12345 }));
|
||||
@@ -571,10 +568,10 @@ describe('GitlabUrlReader', () => {
|
||||
it('should return the file when using a user token', async () => {
|
||||
worker.use(
|
||||
rest.get('*/api/v4/projects/user%2Fproject', (req, res, ctx) => {
|
||||
if (req.headers.get('private-token') !== 'gl-user-token') {
|
||||
if (req.headers.get('authorization') !== 'Bearer gl-user-token') {
|
||||
return res(
|
||||
ctx.status(403),
|
||||
ctx.json({ message: 'Not Authorized' }),
|
||||
ctx.status(401),
|
||||
ctx.json({ message: '401 Unauthorized' }),
|
||||
);
|
||||
}
|
||||
return res(ctx.status(200), ctx.json({ id: 12345 }));
|
||||
@@ -737,10 +734,10 @@ describe('GitlabUrlReader', () => {
|
||||
(_, res, ctx) => res(ctx.status(200), ctx.json({ id: 12345 })),
|
||||
),
|
||||
rest.get('*/api/v4/projects/user%2Fproject', (req, res, ctx) => {
|
||||
if (req.headers.get('private-token') !== 'gl-user-token') {
|
||||
if (req.headers.get('authorization') !== 'Bearer gl-user-token') {
|
||||
return res(
|
||||
ctx.status(403),
|
||||
ctx.json({ message: 'Not Authorized' }),
|
||||
ctx.status(401),
|
||||
ctx.json({ message: '401 Unauthorized' }),
|
||||
);
|
||||
}
|
||||
return res(ctx.status(200), ctx.json({ id: 12345 }));
|
||||
@@ -798,10 +795,10 @@ describe('GitlabUrlReader', () => {
|
||||
(_, res, ctx) => res(ctx.status(404)),
|
||||
),
|
||||
rest.get('*/api/v4/projects/user%2Fproject', (req, res, ctx) => {
|
||||
if (req.headers.get('private-token') !== 'gl-user-token') {
|
||||
if (req.headers.get('authorization') !== 'Bearer gl-user-token') {
|
||||
return res(
|
||||
ctx.status(403),
|
||||
ctx.json({ message: 'Not Authorized' }),
|
||||
ctx.status(401),
|
||||
ctx.json({ message: '401 Unauthorized' }),
|
||||
);
|
||||
}
|
||||
return res(ctx.status(200), ctx.json({ id: 12345 }));
|
||||
@@ -857,21 +854,19 @@ describe('GitlabUrlReader', () => {
|
||||
beforeEach(() => {
|
||||
worker.use(
|
||||
rest.get('*/api/v4/projects/group%2Fproject', (req, res, ctx) => {
|
||||
// the private-token header must be included on API calls
|
||||
if (req.headers.get('private-token') !== 'gl-dummy-token') {
|
||||
if (req.headers.get('authorization') !== 'Bearer gl-dummy-token') {
|
||||
return res(
|
||||
ctx.status(403),
|
||||
ctx.json({ message: 'Not Authorized' }),
|
||||
ctx.status(401),
|
||||
ctx.json({ message: '401 Unauthorized' }),
|
||||
);
|
||||
}
|
||||
return res(ctx.status(200), ctx.json({ id: 12345 }));
|
||||
}),
|
||||
rest.get('*/api/v4/projects/user%2Fproject', (req, res, ctx) => {
|
||||
// the private-token header must be included on API calls
|
||||
if (req.headers.get('private-token') !== 'gl-user-token') {
|
||||
if (req.headers.get('authorization') !== 'Bearer gl-user-token') {
|
||||
return res(
|
||||
ctx.status(403),
|
||||
ctx.json({ message: 'Not Authorized' }),
|
||||
ctx.status(401),
|
||||
ctx.json({ message: '401 Unauthorized' }),
|
||||
);
|
||||
}
|
||||
return res(ctx.status(200), ctx.json({ id: 12345 }));
|
||||
|
||||
@@ -398,6 +398,12 @@ export class GitlabUrlReader implements UrlReaderService {
|
||||
);
|
||||
const data = await result.json();
|
||||
if (!result.ok) {
|
||||
if (result.status === 401) {
|
||||
throw new Error(
|
||||
'GitLab Error: 401 - Unauthorized. The access token used is either expired, or does not have permission to read the project',
|
||||
);
|
||||
}
|
||||
|
||||
throw new Error(`Gitlab error: ${data.error}, ${data.error_description}`);
|
||||
}
|
||||
return Number(data.id);
|
||||
|
||||
@@ -188,7 +188,7 @@ describe('gitlab core', () => {
|
||||
});
|
||||
|
||||
describe('getGitLabRequestOptions', () => {
|
||||
it('should return Authorization header when oauthToken is provided', () => {
|
||||
it('should return Authorization bearer header when a token is provided', () => {
|
||||
const token = '1234567890';
|
||||
const result = getGitLabRequestOptions(
|
||||
configSelfHosteWithRelativePath,
|
||||
@@ -202,29 +202,12 @@ describe('gitlab core', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should return private-token header when gl-token is provided', () => {
|
||||
const token = 'glpat-1234566';
|
||||
const result = getGitLabRequestOptions(
|
||||
configSelfHosteWithRelativePath,
|
||||
token,
|
||||
);
|
||||
it('should return Authorization bearer header using the config token when no token is provided', () => {
|
||||
const result = getGitLabRequestOptions(configSelfHosteWithRelativePath);
|
||||
|
||||
expect(result).toEqual({
|
||||
headers: {
|
||||
'PRIVATE-TOKEN': token,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return private-token header when oauthToken is undefined', () => {
|
||||
const oauthToken = undefined;
|
||||
const result = getGitLabRequestOptions(
|
||||
configSelfHosteWithRelativePath,
|
||||
oauthToken,
|
||||
);
|
||||
expect(result).toEqual({
|
||||
headers: {
|
||||
'PRIVATE-TOKEN': configSelfHosteWithRelativePath.token,
|
||||
Authorization: `Bearer ${configSelfHosteWithRelativePath.token}`,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,20 +56,17 @@ export function getGitLabRequestOptions(
|
||||
config: GitLabIntegrationConfig,
|
||||
token?: string,
|
||||
): { headers: Record<string, string> } {
|
||||
if (token) {
|
||||
// If token comes from the user and starts with "gl", it's a private token (see https://docs.gitlab.com/ee/security/token_overview.html#token-prefixes)
|
||||
return {
|
||||
headers: token.startsWith('gl')
|
||||
? { 'PRIVATE-TOKEN': token }
|
||||
: { Authorization: `Bearer ${token}` }, // Otherwise, it's a bearer token
|
||||
};
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
const accessToken = token || config.token;
|
||||
if (accessToken) {
|
||||
// OAuth, Personal, Project, and Group access tokens can all be passed via
|
||||
// a bearer authorization header
|
||||
// https://docs.gitlab.com/api/rest/authentication/#personalprojectgroup-access-tokens
|
||||
headers.Authorization = `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
// If token not provided, fetch the integration token
|
||||
const { token: configToken = '' } = config;
|
||||
return {
|
||||
headers: { 'PRIVATE-TOKEN': configToken },
|
||||
};
|
||||
return { headers };
|
||||
}
|
||||
|
||||
// Converts
|
||||
@@ -149,6 +146,12 @@ export async function getProjectId(
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
throw new Error(
|
||||
'GitLab Error: 401 - Unauthorized. The access token used is either expired, or does not have permission to read the project',
|
||||
);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`GitLab Error '${data.error}', ${data.error_description}`,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user