I have created a REST service in ColdFusion with a POST. It takes input json from other application, checks them in my DB and returns the http status code. Simple.
Calling it from RESTClient-FireFox Plus from POSTMAN-Chrome, my application says it's success/failure depending upon authentication, but RESTClient hangs continuing to show the progress bar and the button Abort.
The GET works perfectly fine though. Can anyone please help?
GET - Works fine.
POST - Does not work.
Here is my webservice(cfc):
<cfcomponent rest="true" restpath="/AimsWeb"> <!--- REST Service--->
<cffunction name="AuthenticateUser" access="remote" httpmethod="POST" returntype="void">
<!---- Defining Arguments--->
<cfargument name="Username" type="string" required="Yes">
<cfargument name="Password" type="string" required="Yes">
<cfargument name="CustomerID" type="numeric" required="Yes">
<!---- Setting the Form Values (which we will get from AW+) and setting it to arguments passed--->
<cfset Form.CustomerID = arguments.CustomerID>
<cfset Form.Username = arguments.Username>
<cfset Form.Password = arguments.Password>
<!--- Take input json, parse it and set in in a variable --->
<cfscript>
record=deserializeJSON(
'{
"customerId": "#Form.CustomerID#",
"userName": "#Form.userName#",
"password": "#Form.Password#"
}'
);
this.customerid = record.customerId;
this.userName = record.userName;
this.password = record.password;
</cfscript>
<cfdump var="#record#">
<cfquery name="AllUsers" datasource="#Application.GomDatasource#">
SELECT u.UserTypeID, u.UserID, u.CustomerID, u.UserName, u.Password, u.active, u.locked
FROM tblUsers u
WHERE
u.username = 'swapnil'
</cfquery>
<!--- This is to check whether provided parameters are valid by checking the same in the database --->
<cfset local.StatusStruct = StructNew()>
<cflog text="in struct" type="information">
<cfif AllUsers.RecordCount AND (AllUsers.Active EQ 0 OR AllUsers.locked EQ 1)>
<cfheader statuscode="401" statustext="User Account is locked">
<cflog text="account locked" type="information">
<cfelse>
<cfif this.customerid EQ "" OR this.username EQ "" OR this.password EQ "">
<cfheader statuscode="400" statustext="Insufficient Input. Please provide Customer ID, UserName and Password">
<cflog text="insufficient input" type="information">
<cfelseif AllUsers.RecordCount AND (this.CustomerId EQ AllUsers.CustomerID AND this.username EQ AllUsers.UserName AND this.password EQ AllUsers.Password)>
<cfheader statuscode="200" statustext="Success">
<cflog text="success" type="information">
<cfelseif AllUsers.CustomerID NEQ this.CustomerID>
<cfheader statuscode="400" statustext="Customer Id doesn't exist">
<cflog text="customer id not exist" type="information">
<cfelseif AllUsers.UserName NEQ this.UserName>
<cfheader statuscode="400" statustext="User not found">
<cflog text="user name not found" type="information">
<cfoutput>
user name not found
</cfoutput>
<cfelseif AllUsers.Password NEQ this.password>
<cfheader statuscode="400" statustext="Invalid Password">
<cflog text="invalid password" type="information">
</cfif>
</cfif>
</cffunction>
</cfcomponent>
Here is the JSON I am passing as a Body:
{
"customerId": 100,
"userName": "test",
"password": "xxxxx"
}
Related
I'm working on my Application.cfc page for my SPA. So far I was able to create simple test and there is one problem that I notice. Flag that I set when user is loggedin always indicates to true. Here is my Application.cf page example:
<cffunction name="onApplicationStart" access="public" returntype="boolean" output="false">
<cfset APPLICATION.appStarted = now()>
<cfset APPLICATION.appCode = 'SPA'>
<cfset APPLICATION.title = "SPA Application">
<cfset APPLICATION.errorEmails = "myemail#gmail.com">
<cfset APPLICATION.CryptWord = randomSequence()>
<cfset APPLICATION.AppStarted = true>
<cfreturn true>
</cffunction>
<!--- Runs when your session starts --->
<cffunction name="OnSessionStart" access="public" returntype="void" output="false">
<!--- Clear the session. --->
<cfset StructClear( SESSION ) />
<cfset SESSION.loggedin = false>
<cfreturn />
</cffunction>
<!--- Run before the request is processed --->
<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfargument name="thePage" type="string" required="true">
<cfset var page = listLast(arguments.thePage,"/")>
<cfif !listFindNoCase("Login.cfm,Login.cfc",page)>
<cfif !structKeyExists(session, "loggedin") OR session.loggedin EQ false>
<cflocation url="Login.cfm" addToken="false">
</cfif>
</cfif>
<cfreturn true>
</cffunction>
As you can see above I first set some application variables in onApplicationStart() the onSessionStart() first I clear SESSION structure then set flag to false. Here is example of my Login.cfc:
<cfcomponent>
<cffunction name="checkLogin" access="remote" output="false" returnType="boolean">
<cfargument name="username" type="string" required="true">
<cfargument name="password" type="string" required="true">
<cfif arguments.username EQ "test" AND arguments.password EQ "test">
<cfset SESSION.loggedin = true>
<cfreturn true>
<cfelse>
<cfreturn false>
</cfif>
</cffunction>
</cfcomponent>
Then I use cfdump to check my SESSION variable on my Login.cfm (only has HTML form elements and JQuery function to submit the form). Doesn't matter if checkLogin function returns true or false value in loggedin variable is still equal to true. If anyone can see where I'm doing something wrong in my code please let me know. Thank you!
i have written a web service which takes input parameters (json) from other application. i am just authenticating those values and returning the "http status codes and response" (using cfheader). For that I am trying the "RESTClient" in firefox extension. My problem is - It is running the "GET" method successfully but not the POST method.I guess the request is not even going to the server in POST method. See the screen shot below of both the request:
1. GET request
POST request
This is my CFC:
<cfcomponent rest="true" restpath="/AimsWeb"> <!--- REST Service--->
<cffunction name="AuthenticateUser" access="remote" httpmethod="POST" returntype="void">
<!---- Defining Arguments--->
<cfargument name="Username" type="string" required="Yes">
<cfargument name="Password" type="string" required="Yes">
<cfargument name="CustomerID" type="numeric" required="Yes">
<!---- Setting the Form Values (which we will get from AW+) and setting it to arguments passed--->
<cfset Form.CustomerID = arguments.CustomerID>
<cfset Form.Username = arguments.Username>
<cfset Form.Password = arguments.Password>
<!--- Take input json, parse it and set in in a variable --->
<cfscript>
record=deserializeJSON(
'{
"customerId": #Form.CustomerID#,
"userName": "#Form.userName#",
"password": "#Form.Password#"
}'
);
this.customerid = record.customerId;
this.userName = record.userName;
this.password = record.password;
</cfscript>
<cfquery name="AllUsers" datasource="#Application.GomDatasource#">
SELECT u.UserTypeID, u.UserID, u.CustomerID, u.UserName, u.Password, u.active, u.locked
FROM tblUsers u
WHERE u.CustomerID = <cfqueryparam cfsqltype="cf_sql_integer" value="#this.customerid#">
AND u.username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#this.username#">
AND u.password = <cfqueryparam cfsqltype="cf_sql_varchar" value="#this.password#">
</cfquery>
<!--- This is to check whether provided parameters are valid by checking the same in the database--->
<cfset local.StatusStruct = StructNew()>
<cfif AllUsers.RecordCount AND (AllUsers.Active EQ 0 OR AllUsers.locked EQ 1)>
<cfheader statuscode="401" statustext="User Account is locked">
<cfelse>
<cfif this.customerid EQ "" OR this.username EQ "" OR this.password EQ "">
<cfheader statuscode="400" statustext="Insufficient Input. Please provide Customer ID, UserName and Password">
<cfelseif AllUsers.RecordCount AND this.CustomerId EQ AllUsers.CustomerID AND this.username EQ AllUsers.UserName AND this.password EQ AllUsers.Password>
<cfheader statuscode="200" statustext="Success">
<cfelseif AllUsers.CustomerID NEQ this.CustomerID>
<cfheader statuscode="400" statustext="Customer Id doesn't exist">
<cfelseif AllUsers.UserName NEQ this.UserName>
<cfheader statuscode="400" statustext="User not found">
<cfelseif AllUsers.Password NEQ this.password>
<cfheader statuscode="400" statustext="Invalid Password">
</cfif>
</cfif>
</cffunction>
</cfcomponent>
FYI a GET request has no request entity body because it is a GET request and the web server will generally ignore any body included in the request. I am surprised that ColdFusion provides a response since I don't see a GET method in your CFC.
The POST method is probably failing because the CFC is expecting a MIME type of application/form-url-encoded (your CFARGUMENTs) and you are posting application/json
Try breaking up into 2 functions, one which accepts application/json, one application/form-url-encoded
use the 'consumes' attribute in the CFFUNCTION to distinguish. They can both call a common function after this.
I have written a web-service in ColdFusion which returns message (success/failure) by checking the input values in the database.
To run the cfc, I am directly providing the arguments in the URL, like this:
http://localhost/AimsWeb/Authenticate2.cfc?method=AuthenticateUser&returnformat=json&CustomerID=1&username=xxx&password=xxxx
But when I run this page, it ends with an error like below:
This is my CFC:
<cfcomponent rest="true" restpath="/AimsWeb"> <!--- REST Service--->
<cffunction name="AuthenticateUser" access="remote" httpmethod="POST" returnFormat="JSON" returntype="json">
<!---- Defining Arguments--->
<cfargument name="Username" type="string" required="Yes">
<cfargument name="Password" type="string" required="Yes">
<cfargument name="CustomerID" type="string" required="Yes">
<!---- Setting the Form Values (which we will get from AW+) and setting it to arguments passed--->
<cfset Form.CustomerID = arguments.CustomerID>
<cfset Form.Username = arguments.Username>
<cfset Form.Password = Hash(arguments.Password)>
<cfif StructKeyExists (form, 'CustomerID') and StructKeyExists(form, 'UserName') and StructKeyExists (form, 'password')>
<cfquery name="AllUsers" datasource="#Application.GomDatasource#">
SELECT u.UserTypeID, u.UserID, u.CustomerID, u.UserName, u.Password
FROM tblUsers u
WHERE u.CustomerID = <cfqueryparam cfsqltype="cf_sql_integer" value="#Form.CustomerID#">
</cfquery>
<!--- This is to check whether provided parameters are valid by checking the same in the database--->
<cfset local.StatusStruct = StructNew()>
<cfif form.customerid EQ "" OR form.username EQ "" OR form.password EQ "">
<cfset local.StatusStruct['errorCode'] = 400>
<cfset local.StatusStruct['errorMessage'] = "Insufficient Input.">
<cfelseif AllUsers.RecordCount AND form.CustomerId EQ AllUsers.CustomerID AND form.username EQ AllUsers.UserName AND form.password EQ AllUsers.Password>
<cfset local.StatusStruct['errorCode'] = 200>
<cfset local.StatusStruct['errorMessage'] = "Success">
<cfelseif AllUsers.CustomerID NEQ form.CustomerID>
<cfset local.StatusStruct['errorCode'] = 400>
<cfset local.StatusStruct['errorMessage'] = "Customer Id doesn't exist">
<cfelseif AllUsers.UserName NEQ form.UserName>
<cfset local.StatusStruct['errorCode'] = 400>
<cfset local.StatusStruct['errorMessage'] = "User not found">
<cfelseif AllUsers.Password NEQ form.password>
<cfset local.StatusStruct['errorCode'] = 400>
<cfset local.StatusStruct['errorMessage'] = "Invalid Password">
</cfif>
<!--- Returning the status in JSON form--->
</cfif>
<cfreturn local.StatusStruct>
</cffunction>
</cfcomponent>
Can anyone help me please?
it worked. The returntype=json was not valid. I removed that line and it worked.
<cffunction name="AuthenticateUser" access="remote" httpmethod="GET" returnFormat="JSON">
Thanks ALL for your help.
I have a web service (cfc) which will catch/receive JSON data from an external application that would be posting information.
The input request will be in JSON similar to below format:
So I will be receiving CustomerId, UserName and Password and I just need to validate this fields in my database and return the success/failure message.
My question is - How to receive the json data in my cfc? I have written Form scope as I believe it would solve my purpose, but I am not sure.
Also how to parse that json values?
Below is my CFC:
<cfcomponent rest="true" restpath="/AimsWeb"> <!--- REST Service--->
<cffunction name="AuthenticateUser" access="remote" httpmethod="GET" returntype="any">
<!---- Defining Arguments--->
<cfargument name="Username" type="string" required="Yes">
<cfargument name="Password" type="string" required="Yes">
<cfargument name="CustomerID" type="string" required="Yes">
<!---- Setting the Form Values (which we will get from AW+) and setting it to arguments passed--->
<cfset Form.CustomerID = arguments.CustomerID>
<cfset Form.Username = arguments.Username>
<cfset Form.Password = arguments.Password>
<cfif StructKeyExists (form, 'CustomerID') and StructKeyExists(form, 'UserName') and StructKeyExists (form, 'password')>
<cfquery name="AllUsers" datasource="#Application.GomDatasource#">
SELECT u.UserTypeID, u.UserID, u.CustomerID, u.UserName, u.Password, u.active, u.locked
FROM tblUsers u
WHERE u.username = 'vasu'
AND u.CustomerID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Form.CustomerId#">
<!--- OR u.username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Form.userName#"> --->
<!--- OR u.password = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Form.password#"> --->
</cfquery>
<!--- This is to check whether provided parameters are valid by checking the same in the database--->
<cfset local.StatusStruct = StructNew()>
<!--- <cfdump var="#AllUsers#"> --->
<cfif AllUsers.RecordCount AND (AllUsers.Active EQ 0 OR AllUsers.locked EQ 1)>
<cfset local.StatusStruct['errorCode'] = 401>
<cfset local.StatusStruct['errorMessage'] = " User Account is locked">
<cfelse>
<cfif form.customerid EQ "" OR form.username EQ "" OR form.password EQ "">
<cfset local.StatusStruct['errorCode'] = 400>
<cfset local.StatusStruct['errorMessage'] = " Insufficient Input. Please provide Customer ID, UserName and Password">
<cfelseif AllUsers.RecordCount AND form.CustomerId EQ AllUsers.CustomerID AND form.username EQ AllUsers.UserName AND form.password EQ AllUsers.Password>
<cfset local.StatusStruct['errorCode'] = 200>
<cfset local.StatusStruct['errorMessage'] = " Success">
<cfelseif AllUsers.CustomerID NEQ form.CustomerID>
<cfset local.StatusStruct['errorCode'] = 400>
<cfset local.StatusStruct['errorMessage'] = " Customer Id doesn't exist">
<cfelseif AllUsers.UserName NEQ form.UserName>
<cfset local.StatusStruct['errorCode'] = 400>
<cfset local.StatusStruct['errorMessage'] = " User not found">
<cfelseif AllUsers.Password NEQ form.password>
<cfset local.StatusStruct['errorCode'] = 400>
<cfset local.StatusStruct['errorMessage'] = " Invalid Password">
</cfif>
</cfif>
</cfif>
<cfreturn local.StatusStruct> <!--- Returning the status in JSON form--->
</cffunction>
</cfcomponent>
Is there a recommended (and preferably free) way in ColdFusion to access a remote file that is protected by NTLM authentication? The cfhttp tag appears to only support Basic authentication.
This CFX Tag - CFX_HTTP5 - should do what you need. It does cost $50, but perhaps it's worth the cost? Seems like a small price to pay.
Here is some code I found in:
http://www.bpurcell.org/downloads/presentations/securing_cfapps_examples.zip
There are also examples for ldap, webservices, and more.. I'll paste 2 files here so you can have an idea, code looks like it should still work.
<cfapplication name="example2" sessionmanagement="Yes" loginStorage="Session">
<!-- Application.cfm -->
<!-- CFMX will check for authentication with each page request. -->
<cfset Request.myDomain="allaire">
<cfif isdefined("url.logout")>
<CFLOGOUT>
</cfif>
<cflogin>
<cfif not IsDefined("cflogin")>
<cfinclude template="loginform.cfm">
<cfabort>
<cfelse>
<!--Invoke NTSecurity CFC -->
<cfinvoke component = "NTSecurity" method = "authenticateAndGetGroups"
returnVariable = "userRoles" domain = "#Request.myDomain#"
userid = "#cflogin.name#" passwd = "#cflogin.password#">
<cfif userRoles NEQ "">
<cfloginuser name = "#cflogin.name#" password = "#cflogin.password#" roles="#stripSpacesfromList(userRoles)#">
<cfset session.displayroles=stripSpacesfromList(userRoles)><!--- for displaying roles only --->
<cfelse>
<cfset loginmessage="Invalid Login">
<cfinclude template="loginform.cfm">
<cfabort>
</cfif>
</cfif>
</cflogin>
<!-- strips leading & trailing spaces from the list of roles that was returned -->
<cffunction name="stripSpacesfromList">
<cfargument name="myList">
<cfset myArray=listtoarray(arguments.myList)>
<cfloop index="i" from="1" to="#arraylen(myArray)#" step="1">
<!--- <cfset myArray[i]=replace(trim(myArray[i]), " ", "_")>
out<br>--->
<cfset myArray[i]=trim(myArray[i])>
</cfloop>
<cfset newList=arrayToList(myArray)>
<cfreturn newList>
</cffunction>
This is the cfc that might be of interest to you:
<!---
This component implements methods for use for NT Authentication and Authorization.
$Log: NTSecurity.cfc,v $
Revision 1.1 2002/03/08 22:40:41 jking
Revision 1.2 2002/06/26 22:46 Brandon Purcell
component for authentication and authorization
--->
<cfcomponent name="NTSecurity" >
<!--- Authenticates the user and outputs true on success and false on failure. --->
<cffunction name="authenticateUser" access="REMOTE" output="no" static="yes" hint="Authenticates the user." returntype="boolean">
<cfargument name="userid" type="string" required="true" />
<cfargument name="passwd" type="string" required="true" />
<cfargument name="domain" type="string" required="true" />
<cftry>
<cfscript>
ntauth = createObject("java", "jrun.security.NTAuth");
ntauth.init(arguments.domain);
// authenticateUser throws an exception if it fails,
ntauth.authenticateUser(arguments.userid, arguments.passwd);
</cfscript>
<cfreturn true>
<cfcatch>
<cfreturn false>
</cfcatch>
</cftry>
</cffunction>
<!---
Authenticates the user and outputs true on success and false on failure.
--->
<cffunction access="remote" name="getUserGroups" output="false" returntype="string" hint="Gets user groups." static="yes">
<cfargument name="userid" type="string" required="true" />
<cfargument name="domain" type="string" required="true" />
<cftry>
<cfscript>
ntauth = createObject("java", "jrun.security.NTAuth");
ntauth.init(arguments.domain);
groups = ntauth.GetUserGroups(arguments.userid);
// note that groups is a java.util.list, which should be
// equiv to a CF array, but it's not right now???
groups = trim(groups.toString());
groups = mid(groups,2,len(groups)-2);
</cfscript>
<cfreturn groups>
<cfcatch>
<cflog text="Error in ntsecurity.cfc method getUserGroups - Error: #cfcatch.message#" type="Error" log="authentication" file="authentication" thread="yes" date="yes" time="yes" application="no">
<cfreturn "">
</cfcatch>
</cftry>
</cffunction>
<!---
This method combines the functionality of authenticateUser and getUserGroups.
--->
<cffunction access="remote" name="authenticateAndGetGroups" output="false" returntype="string" hint="Authenticates the user and gets user groups if it returns nothing the user is not authticated" static="yes">
<cfargument name="userid" type="string" required="true" />
<cfargument name="passwd" type="string" required="true" />
<cfargument name="domain" type="string" required="true" />
<cftry>
<cfscript>
ntauth = createObject("java", "jrun.security.NTAuth");
ntauth.init(arguments.domain);
// authenticateUser throws an exception if it fails,
// so we don't have anything specific here
ntauth.authenticateUser(arguments.userid, arguments.passwd);
groups = ntauth.GetUserGroups(arguments.userid);
// note that groups is a java.util.list, which should be
// equiv to a CF array, but it's not right now
groups = trim(groups.toString());
groups = mid(groups,2,len(groups)-2);
</cfscript>
<cfreturn groups>
<cfcatch>
<cfreturn "">
</cfcatch>
</cftry>
</cffunction>
</cfcomponent>
If the code from Brandon Purcell that uses the jrun.security.NTauth class doesn't work for you in cf9 (it didn't for me) the fix is to use the coldfusion.security.NTAuthentication class instead. Everything worked fine for me.
You could try following the guidance here: http://cfsilence.com/blog/client/index.cfm/2008/3/17/ColdFusionSharepoint-Integration--Part-1--Authenticating
Here is what it boils down to you doing:
edit the client-config.wsdd
Change
<transport
name="http"
pivot="java:org.apache.axis.transport.http.HTTPSender">
</transport>
to
<transport
name="http"
pivot="java:org.apache.axis.transport.http.CommonsHTTPSender">
</transport>
In my case I fixed this problem using 'NTLM Authorization Proxy Server'
http://www.tldp.org/HOWTO/Web-Browsing-Behind-ISA-Server-HOWTO-4.html
work fine for me :)