-
Notifications
You must be signed in to change notification settings - Fork 140
SNOW-1825789 Secure token cache #1012
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
lib/file_util.js
Outdated
const permission = mode & 0o777; | ||
|
||
//This should be 600 permission, which means the file permission has not been changed by others. | ||
const octalPermissions = permission.toString(8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it duplication of validateOnlyUserReadWritePermissionAndOwner method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is very similar, but operates on file handles in order to mitigate any manipulations between our checks and operations. validateOnlyUserReadWritePermissionAndOwner
should probably be replaced with this later on, but I didn't want to do it in this PR. See https://snowflakecomputing.atlassian.net/browse/SNOW-1944224
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue you attached doesn't address the migration of control for configuration files. Do we need to create a new issue?
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1012 +/- ##
==========================================
+ Coverage 88.85% 88.98% +0.12%
==========================================
Files 73 73
Lines 7034 7151 +117
==========================================
+ Hits 6250 6363 +113
- Misses 784 788 +4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
if (!Util.exists(cacheStat)) { | ||
const options = { recursive: true }; | ||
if (process.platform !== 'win32') { | ||
options.mode = 0o700; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are using here 0o700 permissions and recursive. This is problematic since for example:
0o700
is too narrow for $HOME/.cache directory (this directory has usually 0755 on mac and linux systems)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair, changed to creating recursively with 0o755
, then changing the final directory's permission to 0o700
await fs.mkdir(cacheDir, options); | ||
return true; | ||
} else { | ||
if (!stat.isDirectory()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stat or cacheStat?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, fixed
if (process.platform === 'win32') { | ||
return true; | ||
} | ||
if ((cacheStat.mode & 0o777) === 0o700) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also check owner
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
candidates.push({ folder: credentialCacheDir, subfolders: [] }); | ||
} | ||
const sfTemp = process.env.SF_TEMPORARY_CREDENTIAL_CACHE_DIR; | ||
if (Util.exists(sfTemp)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking if this exists
seems like redundant code. Can we do it in tryTokenDir
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
lib/file_util.js
Outdated
const permission = mode & 0o777; | ||
|
||
//This should be 600 permission, which means the file permission has not been changed by others. | ||
const octalPermissions = permission.toString(8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why convert it to string? just compare with octal value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was copied from an analogous function, fixed
await validateOnlyUserReadWritePermissionAndOwner(tokenCacheFile); | ||
return tokenCacheFile; | ||
const tokenCacheFile = path.join(tokenDir, 'credential_cache_v1.json'); | ||
return [await getSecureHandle(tokenCacheFile, fs.constants.O_RDWR | fs.constants.O_CREAT, fs), tokenCacheFile]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have an issue with how this function is used and O_CREAT flag. It seems to me that it will create cache file (empty one) during read-only operations (retrieving key), and creating file lock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, changed
Logger.getInstance().warn('Could not acquire lock on cache file %s', file); | ||
return null; | ||
} | ||
const res = await fun(fileHandle, file); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Can you more the file locking functionality to a seperate object/functions? I would like this function to look similar to this:
const lck = lockFile()
const res = func(fileHandle, file)
lck.unlock()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed it a bit, is this better?
candidates.push({ folder: xdgCache, subfolders: ['snowflake'] }); | ||
} | ||
const home = process.env.HOME; | ||
switch (process.platform) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: it's hard to see what's returned for each system. Can you do it like this
switch(proces.platform) {
case 'win32':
return [ ... ]
case 'linux':
return [ ... ]
case 'darwin':
return [ ... ]
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't do exactly that, but without the null/undefined checks the function is much more readable now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good
return false; | ||
} | ||
const cacheStat = await fs.lstat(cacheDir).catch((err) => { | ||
if (err.code !== 'ENOENT') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe create dir here when ENOENT? Then stat it again and recover from error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, changed that
🎉 Snyk checks have passed. No issues have been found so far.✅ security/snyk check is complete. No issues have been found. (View Details) ✅ license/snyk check is complete. No issues have been found. (View Details) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One new comment to create follow-up issue.
Code LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, but please look at the comments before merging
if (!Util.exists(jsonCredential[tokenMapKey])) { | ||
jsonCredential[tokenMapKey] = {}; | ||
} | ||
jsonCredential[tokenMapKey][keyHash] = token; | ||
|
||
try { | ||
const flag = Util.exists(fileHandle) ? fs.constants.O_RDWR | fs.constants.O_CREAT : fs.constants.O_WRONLY; | ||
const flag = Util.exists(fileHandle) ? fs.constants.O_WRONLY : fs.constants.O_RDWR | fs.constants.O_CREAT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why ternary? isn't it always O_RDWR | O_CREAT?
No description provided.