Skip to content

Commit

Permalink
Merge pull request #1404 from guardian/ahe/newspaper-archive-check-su…
Browse files Browse the repository at this point in the history
…pport

Newspaper Archive auth endpoint - check supporter entitlement
  • Loading branch information
andrewHEguardian authored Oct 23, 2024
2 parents a37d4af + 27df4b6 commit b516bc6
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 51 deletions.
48 changes: 24 additions & 24 deletions server/apiProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,30 +88,6 @@ export const proxyApiHandler =
outgoingURL,
};

const authorizationOrCookieHeader = async ({
req,
host,
}: {
req: Request;
host: string;
}): Promise<Headers> => {
// If Okta is disabled, always return the cookie header
const { useOkta } = await getOktaConfig();
if (!useOkta) {
return {
Cookie: getCookiesOrEmptyString(req),
};
}
switch (host) {
case 'members-data-api.' + conf.DOMAIN:
return {
Authorization: `Bearer ${req.signedCookies[OAuthAccessTokenCookieName]}`,
};
default:
return {};
}
};

fetch(outgoingURL, {
method: httpMethod,
body: requestBody,
Expand Down Expand Up @@ -193,6 +169,30 @@ export const proxyApiHandler =
});
};

export const authorizationOrCookieHeader = async ({
req,
host,
}: {
req: Request;
host: string;
}): Promise<Headers> => {
// If Okta is disabled, always return the cookie header
const { useOkta } = await getOktaConfig();
if (!useOkta) {
return {
Cookie: getCookiesOrEmptyString(req),
};
}
switch (host) {
case 'members-data-api.' + conf.DOMAIN:
return {
Authorization: `Bearer ${req.signedCookies[OAuthAccessTokenCookieName]}`,
};
default:
return {};
}
};

export const customMembersDataApiHandler = proxyApiHandler(
'members-data-api.' + conf.DOMAIN,
);
Expand Down
96 changes: 69 additions & 27 deletions server/routes/newspaperArchive.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Router } from 'express';
import type { Request, Response } from 'express';
import fetch from 'node-fetch';
import { authorizationOrCookieHeader } from '../apiProxy';
import { s3ConfigPromise } from '../awsIntegration';
import { conf } from '../config';
import { log } from '../log';
import { withIdentity } from '../middleware/identityMiddleware';

Expand Down Expand Up @@ -32,40 +34,80 @@ const router = Router();
router.use(withIdentity(401));

router.get('/auth', async (req: Request, res: Response) => {
const config = await newspaperArchiveConfigPromise;
const authString = config?.authString;
if (authString === undefined) {
log.error(`Missing newspaper archive auth key`);
res.status(500).send();
}
try {
const config = await newspaperArchiveConfigPromise;
const authString = config?.authString;
if (authString === undefined) {
log.error(`Missing newspaper archive auth key`);
return res.sendStatus(500);
}

const hasCorrectEntitlement = await checkSupporterEntitlement(req);

const authHeader = base64(`${authString}`);
const requestBody: NewspapersRequestBody = {};
if (!hasCorrectEntitlement) {
// ToDo: show the user an error/info page
return res.redirect('/');
}

const response = await fetch(
'https://www.newspapers.com/api/userauth/public/get-tpa-token',
{
headers: {
Authorization: `Basic ${authHeader}`,
'Content-Type': 'application/json',
const authHeader = base64(`${authString}`);
const requestBody: NewspapersRequestBody = {};

const response = await fetch(
'https://www.newspapers.com/api/userauth/public/get-tpa-token',
{
headers: {
Authorization: `Basic ${authHeader}`,
'Content-Type': 'application/json',
},
method: 'POST',
body: JSON.stringify(requestBody),
},
method: 'POST',
body: JSON.stringify(requestBody),
},
);
);

const responseJson = (await response.json()) as NewspapersResponseBody;
// ToDo: we have zod on the server, we could parse the responses with that
const responseJson = (await response.json()) as NewspapersResponseBody;

const archiveReturnUrlString = req.query['ncom-return-url'];
if (archiveReturnUrlString && typeof archiveReturnUrlString === 'string') {
const tpaToken = new URL(responseJson.url).searchParams.get('tpa');
const archiveReturnUrlString = req.query['ncom-return-url'];
if (
archiveReturnUrlString &&
typeof archiveReturnUrlString === 'string'
) {
const tpaToken = new URL(responseJson.url).searchParams.get('tpa');

const archiveReturnUrl = new URL(archiveReturnUrlString);
archiveReturnUrl.searchParams.set('tpa', tpaToken ?? '');
return res.redirect(archiveReturnUrl.toString());
}
const archiveReturnUrl = new URL(archiveReturnUrlString);
archiveReturnUrl.searchParams.set('tpa', tpaToken ?? '');
return res.redirect(archiveReturnUrl.toString());
}

return res.redirect(responseJson.url);
return res.redirect(responseJson.url);
} catch (e) {
log.error(
`Something went wrong authenticating with newspapers.com. ${e}`,
);
return res.sendStatus(500);
}
});

export { router };

async function checkSupporterEntitlement(req: Request): Promise<boolean> {
const supporterAttributesResponse = await getSupporterStatus(req);
const supporterAttributes = await supporterAttributesResponse.json();

// ToDo: this should return a flag that represents either Tier 3 or a newspaperArchive specific entitlement
return (
supporterAttributes.contentAccess['guardianWeeklySubscriber'] &&
supporterAttributes.contentAccess['supporterPlus']
);
}

async function getSupporterStatus(req: Request) {
const host = 'members-data-api.' + conf.DOMAIN;

return fetch(`https://${host}/user-attributes/me`, {
method: 'GET',
headers: {
...(await authorizationOrCookieHeader({ req, host })),
},
});
}

0 comments on commit b516bc6

Please sign in to comment.