fix(core): Open oauth callback endpoints to be public (#3168)

This commit is contained in:
Omar Ajoue 2022-04-25 10:51:50 +02:00 committed by GitHub
parent 0448feec56
commit 01807d6136
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 13 deletions

View file

@ -753,3 +753,13 @@ export async function getCredentialForUser(
return sharedCredential.credentials as ICredentialsDb; return sharedCredential.credentials as ICredentialsDb;
} }
/**
* Get a credential without user check
*/
export async function getCredentialWithoutUser(
credentialId: string,
): Promise<ICredentialsDb | undefined> {
const credential = await Db.collections.Credentials.findOne(credentialId);
return credential;
}

View file

@ -137,6 +137,7 @@ import {
WorkflowHelpers, WorkflowHelpers,
WorkflowRunner, WorkflowRunner,
getCredentialForUser, getCredentialForUser,
getCredentialWithoutUser,
} from '.'; } from '.';
import config from '../config'; import config from '../config';
@ -1822,18 +1823,18 @@ class App {
LoggerProxy.error( LoggerProxy.error(
'OAuth1 callback failed because of insufficient parameters received', 'OAuth1 callback failed because of insufficient parameters received',
{ {
userId: req.user.id, userId: req.user?.id,
credentialId, credentialId,
}, },
); );
return ResponseHelper.sendErrorResponse(res, errorResponse); return ResponseHelper.sendErrorResponse(res, errorResponse);
} }
const credential = await getCredentialForUser(credentialId, req.user); const credential = await getCredentialWithoutUser(credentialId);
if (!credential) { if (!credential) {
LoggerProxy.error('OAuth1 callback failed because of insufficient user permissions', { LoggerProxy.error('OAuth1 callback failed because of insufficient user permissions', {
userId: req.user.id, userId: req.user?.id,
credentialId, credentialId,
}); });
const errorResponse = new ResponseHelper.ResponseError( const errorResponse = new ResponseHelper.ResponseError(
@ -1883,7 +1884,7 @@ class App {
oauthToken = await requestPromise(options); oauthToken = await requestPromise(options);
} catch (error) { } catch (error) {
LoggerProxy.error('Unable to fetch tokens for OAuth1 callback', { LoggerProxy.error('Unable to fetch tokens for OAuth1 callback', {
userId: req.user.id, userId: req.user?.id,
credentialId, credentialId,
}); });
const errorResponse = new ResponseHelper.ResponseError( const errorResponse = new ResponseHelper.ResponseError(
@ -1913,13 +1914,13 @@ class App {
await Db.collections.Credentials!.update(credentialId, newCredentialsData); await Db.collections.Credentials!.update(credentialId, newCredentialsData);
LoggerProxy.verbose('OAuth1 callback successful for new credential', { LoggerProxy.verbose('OAuth1 callback successful for new credential', {
userId: req.user.id, userId: req.user?.id,
credentialId, credentialId,
}); });
res.sendFile(pathResolve(__dirname, '../../templates/oauth-callback.html')); res.sendFile(pathResolve(__dirname, '../../templates/oauth-callback.html'));
} catch (error) { } catch (error) {
LoggerProxy.error('OAuth1 callback failed because of insufficient user permissions', { LoggerProxy.error('OAuth1 callback failed because of insufficient user permissions', {
userId: req.user.id, userId: req.user?.id,
credentialId: req.query.cid, credentialId: req.query.cid,
}); });
// Error response // Error response
@ -2084,11 +2085,11 @@ class App {
return ResponseHelper.sendErrorResponse(res, errorResponse); return ResponseHelper.sendErrorResponse(res, errorResponse);
} }
const credential = await getCredentialForUser(state.cid, req.user); const credential = await getCredentialWithoutUser(state.cid);
if (!credential) { if (!credential) {
LoggerProxy.error('OAuth2 callback failed because of insufficient permissions', { LoggerProxy.error('OAuth2 callback failed because of insufficient permissions', {
userId: req.user.id, userId: req.user?.id,
credentialId: state.cid, credentialId: state.cid,
}); });
const errorResponse = new ResponseHelper.ResponseError( const errorResponse = new ResponseHelper.ResponseError(
@ -2129,7 +2130,7 @@ class App {
!token.verify(decryptedDataOriginal.csrfSecret as string, state.token) !token.verify(decryptedDataOriginal.csrfSecret as string, state.token)
) { ) {
LoggerProxy.debug('OAuth2 callback state is invalid', { LoggerProxy.debug('OAuth2 callback state is invalid', {
userId: req.user.id, userId: req.user?.id,
credentialId: state.cid, credentialId: state.cid,
}); });
const errorResponse = new ResponseHelper.ResponseError( const errorResponse = new ResponseHelper.ResponseError(
@ -2180,7 +2181,7 @@ class App {
if (oauthToken === undefined) { if (oauthToken === undefined) {
LoggerProxy.error('OAuth2 callback failed: unable to get access tokens', { LoggerProxy.error('OAuth2 callback failed: unable to get access tokens', {
userId: req.user.id, userId: req.user?.id,
credentialId: state.cid, credentialId: state.cid,
}); });
const errorResponse = new ResponseHelper.ResponseError( const errorResponse = new ResponseHelper.ResponseError(
@ -2214,7 +2215,7 @@ class App {
// Save the credentials in DB // Save the credentials in DB
await Db.collections.Credentials!.update(state.cid, newCredentialsData); await Db.collections.Credentials!.update(state.cid, newCredentialsData);
LoggerProxy.verbose('OAuth2 callback successful for new credential', { LoggerProxy.verbose('OAuth2 callback successful for new credential', {
userId: req.user.id, userId: req.user?.id,
credentialId: state.cid, credentialId: state.cid,
}); });

View file

@ -66,6 +66,8 @@ export function addRoutes(this: N8nApp, ignoredEndpoints: string[], restEndpoint
req.url.startsWith(`/${restEndpoint}/forgot-password`) || req.url.startsWith(`/${restEndpoint}/forgot-password`) ||
req.url.startsWith(`/${restEndpoint}/resolve-password-token`) || req.url.startsWith(`/${restEndpoint}/resolve-password-token`) ||
req.url.startsWith(`/${restEndpoint}/change-password`) || req.url.startsWith(`/${restEndpoint}/change-password`) ||
req.url.startsWith(`/${restEndpoint}/oauth2-credential/callback`) ||
req.url.startsWith(`/${restEndpoint}/oauth1-credential/callback`) ||
isAuthExcluded(req.url, ignoredEndpoints) isAuthExcluded(req.url, ignoredEndpoints)
) { ) {
return next(); return next();

View file

@ -237,12 +237,16 @@ export declare namespace OAuthRequest {
{}, {},
{}, {},
{ oauth_verifier: string; oauth_token: string; cid: string } { oauth_verifier: string; oauth_token: string; cid: string }
>; > & {
user?: User;
};
} }
namespace OAuth2Credential { namespace OAuth2Credential {
type Auth = OAuth1Credential.Auth; type Auth = OAuth1Credential.Auth;
type Callback = AuthenticatedRequest<{}, {}, {}, { code: string; state: string }>; type Callback = AuthenticatedRequest<{}, {}, {}, { code: string; state: string }> & {
user?: User;
};
} }
} }