-
Notifications
You must be signed in to change notification settings - Fork 304
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
HPCC-30037 Check legacy DZ physical permission in ESP services #17658
Conversation
https://track.hpccsystems.com/browse/HPCC-30037 |
@jakesmith please review the second commit which is based on the commit in #17528. |
@wangkx - before I review, now that https://track.hpccsystems.com/browse/HPCC-29246 is merged, can you rebase and change from draft status? |
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.
@wangkx - please rebase
Rebased |
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.
@wangkx - see comment.
esp/services/ws_fs/ws_fsService.cpp
Outdated
} | ||
//Based on the tests, the dfuserver only supports the wildcard inside the file name, like '/path/f*'. | ||
//The dfuserver throws an error if the wildcard is inside the path, like /p*ath/file. | ||
SecAccessFlags permission = getDZFileScopePermissions(context, sourcePlaneReq, path, sourceIPReq, SecAccess_Read); |
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.
Removing the check on if (dropZone) line 2016 (and elsewhere throughout these changes), doesn't look right.
It is conflating 2 different issues:
- The existence of a valid dropzone definition in the environment (or no match if restrictions are off)
- LDAP checking of that dropzone based on PLANE::::... or failing over to legacy in bare-metal if failover is configured.
If the dropzone in 1) doesn't exist (and was allowed to continue because restrictions off), then it should not continue to scope check.
If the dropzone does exist, it should scope check and that scope checking should failover to legacy physical form if failOverToLegacyPhysicalPerms is on.
NB: it is also wrong in dfurun.cpp, it too should not go on to check if an environment dropzone couldn't be found (and was allowed to proceed because restrictions were off).
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.
If the dropzone in 1) doesn't exist (and was allowed to continue because restrictions off), then it should not continue to scope check.
@jakesmith We still need to check legacy physical form if the failOverToLegacyPhysicalPerms is on, right?
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.
only if dropzone exists. And as noted above, dfurun.cpp should do same.
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.
How about the Foreign File in dfurun.cpp? Should I check legacy physical form there if the failOverToLegacyPhysicalPerms is on?
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.
yes, that is not dependent on whether there's a dropzone or not.
The comments above are only related to what to do when there's no dropzone found (which implies restrictions off too).
@jakesmith please review (I do not keep the previous commit since it is fully changed). |
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.
@wangkx - please see comments
if (permission < SecAccess_Read) | ||
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s %s not allowed for user %s (permission:%s). Read Access Required.", | ||
dropZoneName.str(), netAddressStr.str(), pathStr.str(), context.queryUserId(), getSecAccessFlagName(permission)); | ||
validateDropZoneReq(context, dropZoneName, netAddressStr, pathStr, SecAccess_Read); |
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.
what happens if isDropZoneRestrictionEnabled is disabled?
Can validateDropZoneReq called in this context still throw an error?
Need to make sure all routes are consistent.
It may not be true universally now (?) , but if a dropzone doesn't exist and drop zone restrictions are off, it makes little sense to go on to check any LDAP permissions.
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 validateDropZoneReq() calls the getDZPathScopePermissions() which handles the isDropZoneRestrictionEnabled if a dropzone cannot be found based on host and path (a bug to be fixed inside the error message). All other DZ permission checks in ESP should go through the getDZPathScopePermissions().
Inside the getDZPathScopePermissions(), if a dropzone name is given, but, a dropzone cannot be found based on the name, an exception is thrown. Should the isDropZoneRestrictionEnabled be checked before throwing the exception (see the dfurun for the similar situation)?
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.
See comment in validateDropZoneReq(), this method is only called for upload/download and maybe 'special' if there is zero expectation for it to be used without a dropzone (since it is in response to the UI presenting a list of files in dropzones).
If there are other situations this could be called - and legacy systems have used upload/download without a corresponding dropzone and with useDropZoneRestriction=false , then you will need to careful you don't break backward compatibility by enforcing it now even with useDropZoneRestriction=false
I think it's probably okay, because used in conjunction with UI only - but the semantics and reasoning needs to be clear (with comments)
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s %s not allowed for user %s (permission:%s). Full Access Required.", | ||
dropZoneName.str(), netAddress.str(), path.str(), ctx.queryUserId(), getSecAccessFlagName(permission)); | ||
|
||
validateDropZoneReq(ctx, dropZoneName, netAddress, path, SecAccess_Full); |
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.
same q. as above
esp/services/ws_fs/ws_fsService.cpp
Outdated
@@ -1920,6 +1920,16 @@ static bool parseUNCPath(const char* sprayPath, StringBuffer& localPath, StringB | |||
return true; | |||
} | |||
|
|||
static void validateDZFileScopePermission(IEspContext& context, const char* dropZoneName, const char* path, const char* host, SecAccessFlags permissionReq) |
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 new function is very similar and/or overlapping with the new function you've introduced in ws_fsBinding.cpp.
Which makes it hard to see at a glance why there are multiple functions performing very similar functions and easy to introduce differences and inconsistencies.
At a glance, it looks like the one in ws_fsBinding.cpp, could be calling/reusing this one,
They could do with renaming to clarify their difference too.
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 function calls getDZFileScopePermissions() and the new function in ws_fsBinding.cpp calls getDZPathScopePermissions(). I am going to move (possible rename and merge) them (and the getDZPathScopePermissionsEx()) into TpCommon.cpp.
esp/services/ws_fs/ws_fsService.cpp
Outdated
if (permission < SecAccess_Read) | ||
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s not allowed for user %s (permission:%s). Read Access Required.", | ||
sourcePlaneReq.str(), path, context.queryUserId(), getSecAccessFlagName(permission)); | ||
validateDZFileScopePermission(context, sourcePlaneReq, path, sourceIPReq, SecAccess_Read); |
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 think validateDZFileScopePermission will allow access if dropzone restrictions are disabled, whether or not the dropzone exists .... it shouldn't be checking permissions.
But it's not clear that is the case looking at validateDZFileScopePermission.
In these common helper functions, it would be good if it clearly commented the semantics, including what happens when dropzone restrictions are disabled.
Another reason to ensure as much is common as possible (see other comments)
esp/services/ws_fs/ws_fsService.cpp
Outdated
@@ -2975,6 +2979,15 @@ bool CFileSprayEx::onDFUWUFile(IEspContext &context, IEspDFUWUFileRequest &req, | |||
return true; | |||
} | |||
|
|||
static SecAccessFlags getDZPathScopePermissionsEx(IEspContext &context, const char *dropZoneName, const char *path, |
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 also looks like a very similar function to other new helper functions introduced (a subset).
All these similar functions should be in one place and utilize each other and be clearer how they behave and how they differ.
esp/smc/SMCLib/TpCommon.cpp
Outdated
|
||
//The setExternal() requests the path with a file name. The file name is not used by the getDLFNPermissions(). | ||
//If the dropZoneFile is a path only, the dropZoneScope + a faked file name is passed to the setExternal(). | ||
StringBuffer pathWithFileName(dropZoneFile); |
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 would help if there were 2 functions one for Path and one for File (getLegacyDZPhysicalFilePerms, getLegacyDZPhysicalPathPerms)
And, rather than this workaround for the lack of support from IDistributedFileDirectory for validating a path that isn't a file, it would be better to add support.
What's missing I think is a simple:
IDistributedFileDirectory::getScopePermissions(const char *scopes, ....)
method.
If that is added, then the common code for that getLegacyDZPhysicalFilePerms and getLegacyDZPhysicalPathPerms calls , can use a CDfsLogicalFileName and conditionally do:
if (isPath)
scopesToCheck = dlfn.get();
else
{
dlfn.getScopes(scopes);
scopesToCheck = scopes;
}
return queryDistributedFileDirectory().getScopePermissions(scopesToCheck, userDesc);
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.
@wangkx - looks better, a couple of questions surrounding useDropZoneRestriction in the case of upload/download.
Could still do with more clarification (comments) on the different but very similar functions in TpCommon.cpp.
And, I think there's more scope to rationalize them further, but that can wait for another day.
esp/services/ws_fs/ws_fsBinding.cpp
Outdated
@@ -412,12 +412,7 @@ int CFileSpraySoapBindingEx::downloadFile(IEspContext &context, CHttpRequest* re | |||
pathStr.replace(pathSep=='\\'?'/':'\\', pathSep); | |||
addPathSepChar(pathStr); |
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.
would be slightly clearer to add this after the call to validateDropZoneReq
being here, makes it look like it is required for the call.
esp/smc/SMCLib/TpCommon.cpp
Outdated
return permission; | ||
} | ||
|
||
//Validate dropzone host and file path. Also validate dropzone file permission when the file path does not contain a file name. |
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 is used in 2 contexts, download and upload.
Is it correct that it does not check isDropZoneRestrictionEnabled() ?
Maybe it is ok, because it is expected to be serviced by UI interactions that have listed dropzones - so it is wholly unexpected for their to be a request here without a valid dropzone.
If it is okay, it needs a clear comment as to what this is for and why it does not check isDropZoneRestrictionEnabled() in this case.
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.
when the file path does not contain a file name.
When rewriting the comment I would avoid using 'when' it makes it sound like it could be either a path to a file or a path without a file.
Consistently calling naming the parameter 'path' or 'filePath' would be clearer.
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 problem is inside the validateDropZoneHostAndPath() which is called by validateDropZoneReq() and not check isDropZoneRestrictionEnabled(). It should be fixed because the validateDropZoneHostAndPath() is also called by the FileSpray.FileList. I am working on it now.
if (permission < SecAccess_Read) | ||
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s %s not allowed for user %s (permission:%s). Read Access Required.", | ||
dropZoneName.str(), netAddressStr.str(), pathStr.str(), context.queryUserId(), getSecAccessFlagName(permission)); | ||
validateDropZoneReq(context, dropZoneName, netAddressStr, pathStr, SecAccess_Read); |
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.
See comment in validateDropZoneReq(), this method is only called for upload/download and maybe 'special' if there is zero expectation for it to be used without a dropzone (since it is in response to the UI presenting a list of files in dropzones).
If there are other situations this could be called - and legacy systems have used upload/download without a corresponding dropzone and with useDropZoneRestriction=false , then you will need to careful you don't break backward compatibility by enforcing it now even with useDropZoneRestriction=false
I think it's probably okay, because used in conjunction with UI only - but the semantics and reasoning needs to be clear (with comments)
esp/services/ws_fs/ws_fsService.cpp
Outdated
if (!isEmptyString(dzName) && getDZPathScopePermissions(context, dzName, directoryStr, nullptr) < SecAccess_Read) | ||
return false; | ||
if (!isEmptyString(dzName) && (getDZPathScopePermsAndLegacyPhysicalPerms(context, dzName, directoryStr, netAddress, SecAccess_Read) < SecAccess_Read)) | ||
return false; |
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.
odd indentation
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.
Will fit it
@jakesmith please review my changes. |
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.
@wangkx - looks clearer, and ready. 2 trivial spacing issues.
Please address those and squash
esp/services/ws_fs/ws_fsService.cpp
Outdated
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone %s %s not allowed for user %s (permission:%s). Read Access Required.", | ||
dropZoneName, sPath.str(), context.queryUserId(), getSecAccessFlagName(permission)); | ||
if (isEmptyString(dropZoneName)) | ||
dropZoneName= dropZone->queryProp("@name"); |
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.
trivial/formattnig: spacing around '='
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.
Fixed
esp/smc/SMCLib/TpCommon.cpp
Outdated
|
||
Owned<IPropertyTree> dropZone = getDropZoneAndValidateHostAndPath(dropZoneName, host, filePath); | ||
if (dropZone) | ||
dropZoneName= dropZone->queryProp("@name"); |
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.
trivial/formatting: spacing around '='
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.
Fixed
1. In checkPlaneFilePermissions() (dfurun.cpp), check legacy physical permission only if the plane name is set. 2. Add getLegacyDZPhysicalPerms() in ESP SMCLib. 3. Call getLegacyDZPhysicalPerms() in validateDropZoneAccess() which is used by ESP WsFileIO service. 4. In ESP FileSpray service, check legacy physical permission if plane exists. Revise based on review 1. Add queryDistributedFileDirectory().getFScopePermissions() and call it in the getLegacyDZPhysicalPerms(). 2. Move validateDropZoneReq(), validateDZFileScopePermission() and getDZPathScopePermissionsEx()) into TpCommon.cpp. Rename the getDZPathScopePermissionsEx() to getDZPathScopePermsAndLegacyPhysicalPerms(). Rename the validateDZFileScopePermission() to validateDZFileScopePermissions(). Also revise them. 3. The following 3 files are not called from outside. Change them from extern to static: getDZPathScopePermissions(), getDZFileScopePermissions() and getLegacyDZPhysicalPerms(). 4. Add comments. 5. Fix a bug in the message for the throwOrLogDropZoneLookUpError(). 6. Rename the validateDropZoneHostAndPath() to getDropZoneAndValidateHostAndPath() and revise it. It is called when uploading/downloading dropzone file and in WsFileSprayEx::onFileList(). There are 2 issues in the existing code: a. some code are duplicated with the code in FileSprayEx::onFileList(). b. the isDropZoneRestrictionEnabled is not used. 7. Rename the validateDZFileScopePermissions() to validateDZFileScopePermsAndLegacyPhysicalPerms() 8. Consoliate the code in FileSprayEx::onFileList() by using the getDropZoneAndValidateHostAndPath(). 9. Add validateDZPathScopePermsAndLegacyPhysicalPerms() which contains the common code for the validateDropZoneReq() and WsFileSprayEx. 10. Revise the code in validateDropZoneReq(). 11. Move the addPathSepChar() line, fix an intent bug, and fix a message bug. 12. Add more comments. Signed-off-by: wangkx <[email protected]>
@ghalliday please merge this PR. |
Type of change:
Checklist:
Smoketest:
Testing: