Copy link to clipboard
Copied
Hello Coldfusion community,
I need your suggestion in upload functionality that I recently facing. I have shared network drive where I need to upload the file using cf file. but I can't give permision to service ac on which coldfusion is running. Instead client is given user name and password to us when upload. Is there a way to to pass credential while upload file using cf file? What is alternate way to achieve this?
any help would highly appriciated
Thank You!
Uday, I don't think that will be possible. I assume you are using the CFFILE ACTION="upload", which takes the file (as saved as a temp file during the upload) and then MOVES it to the path named in the DESTINATION of cffile. That move will be done BY CF, on behalf of the user that CF is running as.
I'm not aware of any way to have it somehow detect and use the end-user's identity and use that. While a web server like IIS may have provision to detect and use that for files accessed by way of th
...Copy link to clipboard
Copied
Uday, I don't think that will be possible. I assume you are using the CFFILE ACTION="upload", which takes the file (as saved as a temp file during the upload) and then MOVES it to the path named in the DESTINATION of cffile. That move will be done BY CF, on behalf of the user that CF is running as.
I'm not aware of any way to have it somehow detect and use the end-user's identity and use that. While a web server like IIS may have provision to detect and use that for files accessed by way of the web server, in this case the access is NOT "by way of the web server".
Someone may have a different perspective nad better news for you. And I could have this wrong. I will admit I have not seen it done or even discussed, so I'm going on that.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
You could just pass the credentials via the upload form. I have created the following test example, and it works. 🙂
Notes:
<!--- uploadWithCredentials.cfm --->
<cfif isDefined("Form.FileContents") >
<cfset isValidClient=false>
<cftry>
<cfif isDefined("Form.username") and isDefined("Form.password")>
<cfquery datasource="cf_db" name="validateUploader">
select *
from users
where username=<cfqueryparam cfsqltype="cf_sql_varchar" value="#Form.username#">
and pwd=<cfqueryparam cfsqltype="cf_sql_varchar" value="#Form.password#">
</cfquery>
<cfset isValidClient = validateUploader.recordcount gt 0>
</cfif>
<cfif isValidClient>
<cffile action = "upload"
fileField = "FileContents"
destination = "c:\uploads"
nameConflict = "overwrite">
<cfif cffile.FileWasSaved>Upload done!</cfif>
<cfelse>
Your upload credentials are invalid.
</cfif>
<cfcatch type="any">
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
<cfelse>
<form method="post" action="uploadWithCredentials.cfm" enctype="multipart/form-data">
<input name="FileContents" type="file">
<br>
Username: <input name="username" type="text" required>
<br>
Password: <input name="password" type="text" required>
<br>
<input name="submit" type="submit" value="Upload File">
</form>
</cfif>
:
Copy link to clipboard
Copied
Bkbk, I don't read Uday's original post as saying he wanted a cf page to validate the user's credentials (what you just offered). He said he has a "shared network drive where I need to upload the file using cf file. but I can't give permision to service ac on which coldfusion is running".
So as I discussed in my comments, this is about the permissions with which the cffile upload (what is basically a MOVE to that network drive) takes effect. Your code doesn't show you accommodating that, and indeed I'm not aware of a way to cause that. But if you're saying you did, please clarify also how the username entetd was tied to an identity that DOES have permission for that user to allow the file write/move/upload. It seems that is what Uday would be needing most, though he can clarify.
Copy link to clipboard
Copied
I interpreted your use-case as follows:
I would suggest the following strategy for solving this:
Copy link to clipboard
Copied
There are a few third party Java libraries out there that handle CIFS interactions, some more dated than others. I must stress that I've never tried any of them out, they may or may not be able to handle what you're trying to achieve, but I put them out as something you may wish to explore:
This is an old library, and the web site suggests some newer libraries that may be of more use:
https://github.com/AgNO3/jcifs-ng
https://github.com/codelibs/jcifs
https://github.com/hierynomus/smbj
If you or anyone else manages to get this functioning, I'd be really interested to hear about it, as we have a similar project on the horizon.
Cheers,
Mike.
Copy link to clipboard
Copied
Mike, can you clarify how you envision this would help with Uday's use case?
And is the similar project you have really about having a file uploaded to cf to be stored in a destination that is a network drive, using the end user's (browser user's) authentication? There's simply no provision for that with cffile upload.
Copy link to clipboard
Copied
Hi Charlie,
I was going on @uday22547276rirg 's request for "What is alternate way to achieve this?"
Utilizing one of these libraries should allow files/directories to be manipulated on CIFS shares based on passed credentials. Obviously the user would have to be logged into the ColdFusion application, and their username/password stored somewhere, probably in the session (assuming the credentials for the CF app are the same as those for the share). These could then be passed through the relevant Java objects to manipulate files/directories on the share.
So I guess the steps would be:
Like I said, I've never used these libraries, but in theory, this could all be possible. I might knock up a quick test at some point, now I've piqued my own interest 😉
To your second question, the aim of the upcoming project is to build some kind of file manager/explorer type system that the user could manage files/directories on a Windows share based on their credentials, rather than the ColdFusion Service user's credentials that are used by CFFILE and CFDIRECTORY. We've identified a third party .NET app that can do just that, and we might end up just embedding that in an iframe within our CF app. But before we do that, we're going to investigate if a home grown solution in CF/Java is actually possible.
Cheers,
Mike.
Copy link to clipboard
Copied
I don't see any discussion about the security risk of having the user pass in their windows credentials.
I've been trying to discourage from the beginning the hope that this upload could be done using the user's credentials (obtained somehow implicitly) because cf doesn't support that.
But as I noticed both BKBK and Mike discussing (in their most recent comments) using an uploaded username and password, I see now that Uday actually proposed that in his original post. I missed that.
I just want to say this seems a bad idea, especially if somehow the info would be saved to "batch" execute the uploads. Where would these user credentials be stored? Even if "just in memory", it seems a potentially grave risk.
Uday mentioned his. Net colleagues having been able to do something similar to what he wants. Uday, was their approach REALLY involving a .net app (code you guys wrote) receiving such uploaded credentials? I suggest you really confirm that, because I'd think others would have balked at that for the same reason, though perhaps they didn't see a problem.
I just want to make sure you're not trying to force cf to support something that could get you into trouble if you're not very careful.
BTW, if someone may point out out that cfntauthenticate accepts a user's username and password (presumed to be passed in), note that the sole goal of that is authentication. As a result, you know they ARE authenticated--that those credentials are valid. (This is offered as an alternative to having to create separate login credentials for users.) But again all the tag does is authenticate those credentials. They are not then stored in any way by Cf for reuse. I'd a developer did store them, they'd be in this same situation I'm now describing above.
I'm interested to hear if you guys or anyone reading along thinks I'm overreacting here in this general concern.
Copy link to clipboard
Copied
Charlie, I don't see the security concerns you mention. The implementation could flow as follows:
Copy link to clipboard
Copied
Help us out, bkbk. This "the username and password that allow access to the share", are you asserting its the one uploaded from the user with the file? Or some other?
If the same, my concern stands. If another, how would that solve Uday's need, which was to store the file with that user's credentials?
Copy link to clipboard
Copied
Help us out, bkbk. This "the username and password that allow access to the share", are you asserting its the one uploaded from the user with the file? Or some other?
If the same, my concern stands. If another, how would that solve Uday's need, which was to store the file with that user's credentials?
By @Charlie Arehart
The answer is: the database. I am thinking of, for example, a users table containing the columns
username
password
uploadusername
uploadpassword
Xusername
Xpassword
amongst others. The user's upload credentials will enable ColdFusion to identify the user, hence to obtain any other set of credentials.
That was just to answer your question. I consider the following solution better:
Copy link to clipboard
Copied
Sorry, Bkbk, but I still would contend against both points. (And let's be clear: we're both trying to help Uday or other readers, so this public debate is not any personal attack by us on each other, but just that: a public debate. If only our culture could stomach and indeed encourage more reasoned debate. It helps those who are debating as much as it may help those who watch.)
To your first point, storing credentials in a database is again risky. Well, storing a password HASH is safe, when using that just for validating a password later passed in by a user. But storing it NOT hashed, so as to reuse it in a cfexecute like you proposed, that's where it becomes risky.
And as for your second proposal, by "an account", do you mean one? If so, that doesn't meet Uday's originally stated requirement, of using needing to use the user's credentials for the file access permissions on the share. Or maybe you mean to create some alternative credentials for EACH user, but that has the same problem as my first point here. And even if that's solved somehow, there's then the complication of keeping this alternative set of credentials in sync with the *real ones" (inserts, deletes, etc).
But really, it's been a few days of back and forth between us (and Mike) since the last and only comment from Uday. Maybe he could clarify his original proposal, if we may somehow be misinterpreting it.
If nothing else, Uday, please chime in to help arbitrate the debate. Are we helping with your goal, whether in encouraging or discouraging it? 🙂
Copy link to clipboard
Copied
Charlie, if I understand it correctly, your concerns are about the security implications of passing credentials in this way during the upload process. I can understand that. You've highlighted some points for @uday22547276rirg to consider. So I shall leave it up to @uday22547276rirg .
I consider the original question an interesting use-case. My interest is in researching whether of not we can find a solution to the use-case. In ColdFusion.
Coincidentally, a colleague happens to be looking for a solution in C#/.NET for the same use-case. Which peaked my interest to find a solution in ColdFusion.
I think I have found one - for ColdFusion on Windows. I am currently testing it. Expect a post shortly.
Copy link to clipboard
Copied
Charlie, if I understand it correctly, your concerns are about the security implications of passing credentials in this way during the upload process. I can understand that.
By @BKBK
Actually, no. My concerns with proposals have been with the need to STORE credentials on the server, especially if as Uday requested it would be for each user. And worse, if the credentials would relate to file permissions.
And my original concern (to Uday's request) was that there's not any way I know of for CF to perform file access based on the permissions of the user uploading a file.
But sure, there may be a .Net solution. Uday mentioned that, as did Mike. So sure, if you or anyone can find it, that may be helpful, whether as a .Net thing called somehow from with CF, or as a purely .net thing called instead of cf.
Again, though, it sure would be great if we heard from Uday, with thoughts on all that we 3 have offered. He may guide us in some direction based on his expectations.
Copy link to clipboard
Copied
Charlie, if I understand it correctly, your concerns are about the security implications of passing credentials in this way during the upload process. I can understand that.
By @BKBK
Actually, no. My concerns with proposals have been with the need to STORE credentials on the server, especially if as Uday requested it would be for each user. And worse, if the credentials would relate to file permissions.
By @Charlie Arehart
Oh, I see. I would have thought that passing credentials by means of an upload form is usually a greater security risk than storing credentials on the server.
In any case, let's be realistic. Data even more sensitive than credentials are stored on the server. Besides, the server has access to parts of the application even more sensitive than credentials.It all depends on how much you need a functionality, the risks you're prepared to take and how you mitigate those risks.
By the way, I would disagree with your statement,
"the need to STORE credentials on the server, especially if as Uday requested it would be for each user"
From what I can see, @uday22547276rirg has NOT requested that each user's credentials be stored on the server. The requirement is simply that the user be able to pass his or her credentials to the server during upload. Those credentials wont necessarily be stored. They will only be used to validate the client, in exactly the same way you would validate a login.
My proposal, in particular, makes use of just one set of credentials to copy every client's uploaded file from upload location to the share.
Copy link to clipboard
Copied
Coincidentally, a colleague happens to be looking for a solution in C#/.NET for the same use-case. Which peaked my interest to find a solution in ColdFusion.
I think I have found one - for ColdFusion on Windows. I am currently testing it. Expect a post shortly.
By @BKBK
Here then is a solution. It consists of a CFM page and a CFC.
The CFM page consists of an upload form. To be able to upload a file, the user must enter a valid username/password combination. The CFM will, upon successful upload, invoke the FileProcessor component.
The FileProcessor CFC consists of 2 functions. One function creates a batch file to copy a file from the local drive to a share. The second function runs the batch file, hence doing the copying
<!--- uploadFormWithCredentials.cfm --->
<cfif isDefined("Form.FileContents") >
<cfset isValidClient=false>
<cftry>
<!--- Validate upload client --->
<cfif isDefined("Form.username") and isDefined("Form.password")>
<!--- Client validation code goes here. --->
<!--- Replace the following line with, for example, code that validates credentials using the database. --->
<cfset isValidClient = lcase(Form.username) is "bkbk@bkbkDomain.com" and compare(Form.password, "AbraCaDabrA4_@") eq 0>
</cfif>
<cfif isValidClient>
<!--- Upload file to destination directory --->
<cffile action = "upload"
fileField = "FileContents"
destination = "c:\uploads"
nameConflict = "overwrite">
<cfif cffile.FileWasSaved>
<!--- Upload done! --->
<cfset fileProcessorObject = createobject("component","FileProcessor")>
<!--- The function creates a batch file based on the arguments
fileUploadDriveLetter, shareDriveLetter, sharePath, username,
password, uploadedFileName, fileUploadDir --->
<cfset copyingBatchFileName = fileProcessorObject.createCopyingBatchFile("C","Z","\\zzsfile\Media\testFolder", "bkbk@bkbkDomain.com", "AbraCaDabrA4_@", "#cffile.serverfile#", "#cffile.serverdirectory#")>
<cfset fileProcessorObject.runCopyingBatchFile(copyingBatchFileName)>
File successfully uploaded and copied to share.
</cfif>
<cfelse>
Sorry, you cannot upload. Your upload credentials are not valid.
</cfif>
<cfcatch type="any">
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
<cfelse>
<form method="post" action="uploadFormWithCredentials.cfm" enctype="multipart/form-data">
<input name="FileContents" type="file">
<br> <br>
Username: <input name="username" type="text" required>
<br>
Password: <input name="password" type="text" required>
<br> <br>
<input name="submit" type="submit" value="Upload File">
</form>
</cfif>
.
<!--- FileProcessor.cfc --->
<cfcomponent>
<cffunction name="createCopyingBatchFile" returntype="string" hint="Function returns the name xxx.bat of the batch file created">
<cfargument name="fileUploadDriveLetter" required="yes" type="string">
<cfargument name="shareDriveLetter" required="yes" type="string">
<cfargument name="sharePath" required="yes" type="string">
<cfargument name="username" required="yes" type="string">
<cfargument name="password" required="yes" type="string">
<cfargument name="uploadedFileName" required="yes" type="string">
<cfargument name="fileUploadDir" required="yes" type="string" hint="Default is C:\uploads">
<!--- Give copy of file on share same name as uploaded file --->
<cfset var fileNameOnShare = arguments.uploadedFileName>
<cfset var fileUploadPath = arguments.fileUploadDir & "\" & arguments.uploadedFileName>
<cfset var batFileContent="">
<!--- Use arguments to compose the batch file. The output will be something like: --->
<!---
REM CD to file upload drive
cd C:\
REM Use credentials to establish network connection to share
net use Z: \\zzsfile\Media\testFolder /user:bkbk@bkbkDomain.com "AbraCaDabrA4_@"
REM Copy file from disk to share
copy c:\uploads\test.txt \\zzsfile\Media\testFolder\UploadedTestFile.txt
REM Release the network connection to the share
net use Z: /delete
--->
<cfsavecontent variable="batFileContent">
<cfoutput>
REM CD to file upload drive #chr(10)##chr(13)#
cd #arguments.fileUploadDriveLetter#:\ #chr(10)##chr(13)#
REM Use credentials to establish network connection to share #chr(10)##chr(13)#
net use #arguments.shareDriveLetter#: #arguments.sharePath# /user:#arguments.username# "#arguments.password#" #chr(10)##chr(13)#
REM Copy file from disk to share #chr(10)##chr(13)#
copy #fileUploadPath# #arguments.sharePath#\#fileNameOnShare# #chr(10)##chr(13)#
REM Release the network connection to the share #chr(10)##chr(13)#
net use #arguments.shareDriveLetter#: /delete
</cfoutput>
</cfsavecontent>
<!--- Give copying batch file unique name, using time-stamp --->
<cfset var batchFileName="fileCopy#getTickcount()#.bat">
<!--- Write batch file to disk --->
<!--- Use name lock to prevent access to file while it is being written. --->
<cflock name="fileProcessingLock" timeout="10">
<cffile action="write" file="#expandPath('#batchFileName#')#" output="#batFileContent#">
</cflock>
<cfreturn batchFileName>
</cffunction>
<cffunction name="runCopyingBatchFile" returntype="void">
<cfargument name="batchFileName" required="yes" type="string">
<cflock name="fileProcessingLock" timeout="30">
<!--- Run the batch file to copy the uploaded file to the share --->
<!--- Optional: Save any server comments as an output text file. --->
<cfexecute
name="#expandPath('#arguments.batchFileName#')#"
arguments=" "
outputfile="#expandPath('copyOutput#getTickCount()#.txt')#"
timeout="30">
</cfexecute>
</cflock>
</cffunction>
</cfcomponent>
Copy link to clipboard
Copied
Again, if I'm reading Uday's original post right, he wanted to be able to perform the file write (to the network drive, after the upload) using the end user's credentials. (I've said this from the start, but he's never confirmed either way.)
I don't see your code doing this. Indeed, what is your cfexecute code supposed to be doing that can't be done with cffile? Did you interpret a need for something it didn't do? (I'd said from the start that it can't use the end user's credentials to do the file write.)
I guess we wait to see what Uday has to say, to you and/or to me. Perhaps he'll love what you've done and suggest I've misunderstood him from the beginning.
Copy link to clipboard
Copied
Indeed, what is your cfexecute code supposed to be doing that can't be done with cffile?
By @Charlie Arehart
It copies a file from the local disk to the network share, based on credentials.
Copy link to clipboard
Copied
Ah, I see now. It was a lot of code, and I missed the key points. So your letting the users pass in their windows credentials (username and password) and then building a cfexecute to run command line processes that use those credentials.
Ok, sure. That would seem to be a solution. To be clear, I didn't presume Uday (and his users and his org) would WANT to pass those credentials in. So when I first suggested he couldn't get what he wanted, I was referring to any way to have cf do this ON BEHALF OF the user without such credentials being passed in.
Then an earlier comment of yours talked about storing the credentials into a db (it seemed) and I was arguing against that.
But sure, if he wants to have people pass them in this way, it may do what he wants. Let's see. He's kind of gone awol on us for 10 days.
In any case, I'm sure your code could help others who may find this thread, perhaps especially @TheRealMC. You may even want to put it up on GitHub, which may make it easier for folks to find, promote, etc.
Copy link to clipboard
Copied
I interpreted your question as a search for a proof-of-concept. Namely, whether it is possible to implement code in ColdFusion, where:
The answer to your question is yes. I have provided proof, using ColdFusion on Windows.
Copy link to clipboard
Copied
Hey Guy,
I'm sorry. I did not get a chance to check my mails in few days.
@BKBK you did really a good job and I appreciate it. But our expectation was something else than pass the credential inside the form with each file upload. It is impossible to create millions of username and password and store in db. Even we can't allow to execute any batch file.
Batch file could be a alternative solution but my ask was different. Question was can we upload or perform file operations on network drive without giving the permission to coldfusion service account by providing username and password of network drive to cffile or any similar tag or any CF Java based lib? No batch file.
My .net colleagues achieve this and I'm going to use their dll file in CF by creating the object of .net and use their function by providing the filefield as a parameter.
I hope I'm clear this time.
Thank you @Charlie Arehart . You were correct