api: Add __LOCAL__ as a pattern to Client.validRedirectUris, for OBS local IP installations
This commit is contained in:
parent
5ce2947fea
commit
768f0f541b
|
@ -77,6 +77,43 @@ router.get(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isIp = (ip) =>
|
||||||
|
typeof ip === 'string' &&
|
||||||
|
/^([0-9]{1,3}\.)[0-9]{1,3}$/.test(ip) &&
|
||||||
|
ip
|
||||||
|
.split('.')
|
||||||
|
.every(
|
||||||
|
(num, idx) =>
|
||||||
|
!num.startsWith('0') && Number(num) > (idx === 0 || idx === 3 ? 1 : 0) && Number(num) < (idx === 3 ? 254 : 255),
|
||||||
|
);
|
||||||
|
|
||||||
|
const isLocalIp = (ip) => isIp(ip) && (ip.startsWith('10.') || ip.startsWith('172.16.') || ip.startsWith('192.168.'));
|
||||||
|
|
||||||
|
const isValidRedirectUriFor = (redirectUri) => (redirectUriPattern) => {
|
||||||
|
// Here we have an exception to the security requirements demanded by
|
||||||
|
// https://tools.ietf.org/html/draft-ietf-oauth-security-topics-16#section-2.1,
|
||||||
|
// namely, that we do not always require fully specified redirect URIs. This
|
||||||
|
// is because we cannot know beforehand which IP the OBS will be running at.
|
||||||
|
// But since it is usually accessed via local IP, we can allow all local IP
|
||||||
|
// ranges. This special case must only be used in clients that have a very
|
||||||
|
// restricted maxScope as well, to prevent misuse should an attack through
|
||||||
|
// this be successful.
|
||||||
|
// This special case does however enforce TLS ("https://"), for it prevents
|
||||||
|
// usage in a non-TLS-secured web server. At least passive sniffing of the
|
||||||
|
// token is not possible then. A self-signed and manually verified
|
||||||
|
// certificate should be used for this (though usually we cannot enforce the
|
||||||
|
// actual verification).
|
||||||
|
if (redirectUriPattern === '__LOCAL__') {
|
||||||
|
const url = new URL(redirectUri);
|
||||||
|
if (url.protocol === 'https:' && isLocalIp(url.host) && !url.search && !url.hash) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return redirectUriPattern === redirectUri;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/authorize',
|
'/authorize',
|
||||||
passport.authenticate('session'),
|
passport.authenticate('session'),
|
||||||
|
@ -112,7 +149,8 @@ router.get(
|
||||||
}
|
}
|
||||||
|
|
||||||
// We enforce that the redirectUri exactly matches one of the provided URIs
|
// We enforce that the redirectUri exactly matches one of the provided URIs
|
||||||
if (!client.validRedirectUris.includes(redirectUri)) {
|
const check = isValidRedirectUriFor(redirectUri);
|
||||||
|
if (!client.validRedirectUris.some(check)) {
|
||||||
return returnError(res, 'invalid_request', 'invalid redirect_uri');
|
return returnError(res, 'invalid_request', 'invalid redirect_uri');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue