paulmccarthy

Member
Oct 26, 2010
5
0
51
Good evening,

I have a quick question - I just got off the phone to Hostgator and they told me that I couldn't use the WHM API because I was creating the request in Coldfusion and not PHP.

To me this doesn't make much sense - I thought the whole point of an API is to allow interactivity between different languages and platforms etc?

I have to admit, I'm fairly new to this - but the guy at the other end of the phone was less than convincing so I was hoping that someone may be able to shed some light on this for me!?

Here's the setup:-

I have a membership site on a Microsoft box - this is where the requests will be sent from. On a separate server, I have a Hostgator reseller account with WHM installed (version 11.26.20).

The idea is that members of my membership site can automatically create a hosting account that comes free with the membership.

My current coldfusion script spits out this error:-

"Other Error: COM.Allaire.ColdFusion.HTTPFailure

* Message: Connection Failure: Status code unavailable"

Which concerns me!

So, Coldfusion + WHM - is it possible?

Thanks in advance!!!!
Paul
 

MattDees

Well-Known Member
Apr 29, 2005
416
1
243
Houston, TX
cPanel Access Level
Root Administrator
Our APIs work over basic HTTP POST/GET transactions, so any language capable of doing HTTP requests can work with our APIs.

That being said, some languages can be more difficult than others due to variances in how HTTP is handled between different clients.

I have never had to work with our APIs from coldfusion so I am not aware what you may have to encounter, but if you have any problems please open a thread.
 

purdue512

Registered
Oct 27, 2010
1
0
51
I don't see why this would be a problem. The idea that the API call would HAVE to be PHP defeats much of the reasons APIs were invented.

We use ColdFusion extensively and have never hit an API we couldn't work with. We probably have over 20 APIs under our belt. That being said, there is rarely ColdFusion support or examples.

Can you post a little more detail about what you are trying / getting back. Perhaps I can help.
 

paulmccarthy

Member
Oct 26, 2010
5
0
51
I don't see why this would be a problem. The idea that the API call would HAVE to be PHP defeats much of the reasons APIs were invented.

We use ColdFusion extensively and have never hit an API we couldn't work with. We probably have over 20 APIs under our belt. That being said, there is rarely ColdFusion support or examples.

Can you post a little more detail about what you are trying / getting back. Perhaps I can help.
Hi Purdue,

That's exactly what I thought APIs were used for - I tried explaining this several times to the Hostgator rep but I got the same answer - it can't be done!

So I went and tried anyway :)

I really appreciate you offering to help out - thank you!

Here's my code:-

Code:
<cfset #whmusername# = "whmuser">
<cfset #whmhash# = "hash code here">

<cfset #query# = "https://hostip:2087/json-api/createacct?username=rogers2&plan=whmuser_Member&ip=n&password=testpass&[email protected]&domain=testdomain2.com">

<cfset #whmhash# = REReplace(#whmhash#,"(\r|\n)","","all") >

<cfhttp url=#query# throwonerror="false" username=#whmusername# password=#whmhash# >

<cfif #cfhttp.StatusCode# neq "200 OK">
<cfset #error#="cfhttp threw error "&#cfhttp.StatusCode#&#cfhttp.errorDetail#&" for "&#query# >
<cfthrow detail= #error# />
<cfelse>
<cfoutput>
#cfhttp.filecontent#
</cfoutput>
And here's what I get in return:-

Other Error: Application

cfhttp threw error Connection Failure. Status code unavailable.I/O Exception: peer not authenticated for https://hostip:2087/json-api/[email protected]&domain=testdomain2.com


Any ideas you have would be great!

I have a feeling that this might have something to do with the SSL certificate not being listed as being signed by a trusted source and that I might have to import the PEM file into the JRE library. That's what I'm working on doing next - it's a bit of a stab in the dark though!

Thanks in advance Purdue!
Paul
 

sirdopes

Well-Known Member
PartnerNOC
Sep 25, 2007
141
0
66
The ssl that is installed for cpanel is from a trusted source but is set to the hostname of the server. You can use the hostname so you don't get an error about the ssl. I've never used coldfusion before but I just installed it and am seeing if I can get it working. Have you tried it on port 2086 without the ssl instead?
 

paulmccarthy

Member
Oct 26, 2010
5
0
51
Hi Sirdopes,

Thanks for your reply -

Right, I've had some success here!

So, I've connected to the API and carried out some instructions (account creation etc) successfully! However, here's the thing, I can only connect using port 2086 over standard HTTP and when I send my unencrypted password directly! Not ideal :D

So here's a couple of things:-

1) When I take the code for my successful 2086 connection (with hardcoded password) and change to https and 2087 then I get the "Peer not authenticated" - as I mentioned above.

I have a feeling that this has something to do with the SSL certificate not being listed in the keystore...

2) When I take the code for my successful 2086 connection and use my remote access key (hash)...I get a "403 Forbidden" message.


If I could get one of the above sorted then I lessen my chances of a hacking! 2 of the above would mean I'd have the added benefit of sleeping at night :)

Ideally the SSL needs to be sorted, which is why I'm messing about with this:- Using Keytool to Import SSL Certificates into Sun JDK - TalkingTree.com

Cheers Sirdopes - I appreciate you looking into this :)
Best Regards,
Paul
 

paulmccarthy

Member
Oct 26, 2010
5
0
51
The ssl that is installed for cpanel is from a trusted source but is set to the hostname of the server. You can use the hostname so you don't get an error about the ssl. I've never used coldfusion before but I just installed it and am seeing if I can get it working. Have you tried it on port 2086 without the ssl instead?
I've tried setting that to the hostname - unfortunately I don't think that's the issue.

Have a look at the post in the link above and have a look at the keystore issue that other Coldfusion developers have been getting...I think that's my problem
 

paulmccarthy

Member
Oct 26, 2010
5
0
51
Update:-

I have connected to the WHM API with the hash key now.

Here is the complete script:-

Code:
<cfset #whmusername# = "Insert WHM User Name Here">
<cfset #whmhash# = "Insert Remote Access Key Here">

<cfset #query# = "hostname:2086/json-api/listaccts">

<cfset #whmhash# = REReplace(#whmhash#,"(\r|\n)","","all") >

<cfhttp url=#query# throwonerror="false" method="get">
<cfhttpparam type="header" name="Authorization" value="WHM #whmUser#:#whmhash#"> 
</cfhttp>

<cfdump var="#CFHTTP#">

<cfif #cfhttp.StatusCode# neq "200 OK">
<cfset #error#="cfhttp threw error "&#cfhttp.StatusCode#&#cfhttp.errorDetail#&" for "&#query# >
<cfthrow detail= #error# /><br><br>

<cfelse>
<cfoutput>
#cfhttp.filecontent#
</cfoutput>
</cfif>

This was the key element that I was missing:-

Code:
<cfhttpparam type="header" name="Authorization" value="WHM #whmUser#:#whmhash#">
Now I just need to figure out the SSL issue!
 

openmind

Member
Oct 30, 2007
24
0
51
You gotta love Hostgator for talking balls as normal ;)

I've been playing with this this morning and I've got the basis of a custom tag going now for interfacing with WHM via ColdFusion MX. The custom tag is as follows:

Code:
<!---
Custom tag for interfacing with WHM
---->
<cfprocessingdirective suppresswhitespace="yes">
	<!---required attributes for all calls--->
	<cfparam name="reqatt" default="whmhost,whmuser,whmhash,RequestType,function,result">
	<!---timeout for the request in seconds--->
	<cfparam name="whmtimeout" default="20">
	<!---Response Handler--->
	<cfset Response=structnew()>
	<cftry>
		<!---trim all attributes--->
		<cfloop collection="#attributes#" item="Key">
			<cfset attributes[Key]=Trim(attributes[Key])>
		</cfloop>
		<!---check for the required attributes--->
		<cfloop list="#reqatt#" index="varname">
			<cfset varval="attributes." & varname>
			<cfif NOT IsDefined(varval)>
				<cfthrow type="cf_whm.InvalidAttribute" message="Required Attribute '#VarName#' is missing.">
			</cfif>
			<cfif Evaluate(varval) EQ "">
				<cfthrow type="cf_whm.InvalidAttribute" message="Required Attribute '#VarName#' must not be empty.">
			</cfif>
		</cfloop>
		<!---ensure the RequestType is either xml-api or json-api--->
		<cfif attributes.RequestType NEQ "xml-api" AND attributes.RequestType NEQ "json-api">
			<cfthrow type="cf_whm.InvalidAttribute" message="The RequestType attribute must be set to either xml-api or json-api">
		</cfif>
		<!---trim all breaks from the hash--->
		<cfset whmhash=REReplace(attributes.whmhash,"(\r|\n)","","all") >
		<!---set the base query url--->
		<cfset whmurl=attributes.whmhost & "/" & attributes.RequestType & "/" & attributes.function>
		<!---handler for additional options--->
		<cfparam name="whmquery" default="">
		<!---WHM Functions--->
		<cfswitch expression="#attributes.function#">
			<!---DNS Functions (http://docs.cpanel.net/twiki/bin/view/AllDocumentation/AutomationIntegration/XmlApi#DNS%20functions)--->
			<!---
				Name: adddns
				Function: This function creates a DNS zone.
			--->
			<cfcase value="adddns">
				<cfparam name="add_reqatt" default="domain,ip">
				<cfloop list="#add_reqatt#" index="varname">
					<cfset varval="attributes." & varname>
					<cfif NOT IsDefined(varval)>
						<cfthrow type="cf_whm.InvalidAttribute" message="Required Attribute '#VarName#' is missing.">
					</cfif>
					<cfif Evaluate(varval) EQ "">
						<cfthrow type="cf_whm.InvalidAttribute" message="Required Attribute '#VarName#' must not be empty.">
					</cfif>
				</cfloop>
				<cfset whmquery="domain=" & attributes.domain & "&ip=" & attributes.ip>
				<!---optional parameters--->
				<cfif IsDefined("attributes.dnstemplate")>
					<cfswitch expression="#attributes.dnstemplate#">
						<cfcase value="standard">
							<cfset whmquery=whmquery & "&template=standard">
						</cfcase>
						<cfcase value="simple">
							<cfset whmquery=whmquery & "&template=simple">
						</cfcase>
						<cfcase value="standardvirtualftp">
							<cfset whmquery=whmquery & "&template=standard">
						</cfcase>
						<cfdefaultcase>
							<cfthrow type="cf_whm.InvalidAttribute" message="If defining the dnstemplate attribute it must be set to standard, simple or standardvirtualftp">
						</cfdefaultcase>
					</cfswitch>
				</cfif>
			</cfcase>
			<!---/adddns--->
			<!---
				Name: killdns
				Function: This API function lets you delete a DNS zone.
			--->
			<cfcase value="killdns">
				<cfparam name="add_reqatt" default="domain">
				<cfloop list="#add_reqatt#" index="varname">
					<cfset varval="attributes." & varname>
					<cfif NOT IsDefined(varval)>
						<cfthrow type="cf_whm.InvalidAttribute" message="Required Attribute '#VarName#' is missing.">
					</cfif>
					<cfif Evaluate(varval) EQ "">
						<cfthrow type="cf_whm.InvalidAttribute" message="Required Attribute '#VarName#' must not be empty.">
					</cfif>
				</cfloop>
				<cfset whmquery="domain=" & attributes.domain>
			</cfcase>
			<!---/killdns--->
			<!---
				Name: getzonerecord
				Function: This function will return zone records for a domain.
			--->
			<cfcase value="getzonerecord">
				<!---check for the additional required attributes--->
				<cfparam name="add_reqatt" default="domain,line">
				<cfloop list="#add_reqatt#" index="varname">
					<cfset varval="attributes." & varname>
					<cfif NOT IsDefined(varval)>
						<cfthrow type="cf_whm.InvalidAttribute" message="Required Attribute '#VarName#' is missing.">
					</cfif>
					<cfif Evaluate(varval) EQ "">
						<cfthrow type="cf_whm.InvalidAttribute" message="Required Attribute '#VarName#' must not be empty.">
					</cfif>
				</cfloop>
				<cfset whmquery="domain=" & attributes.domain & "&line=" & attributes.line>
			</cfcase>
			<!---/getzonerecord--->
			<!---
				Name: listzones
				Function: This function will generate a list of all domains and corresponding DNS zones associated with your server.
			--->
			<cfcase value="listzones">
				<!---No additional parameters required--->
			</cfcase>
			<!---/listzones--->
			<!---
				Name: dumpzone
				Function: This function displays the DNS zone configuration for a specific domain. 
			--->
			<cfcase value="dumpzone">
				<!---check for the additional required attributes--->
				<cfparam name="add_reqatt" default="domain">
				<cfloop list="#add_reqatt#" index="varname">
					<cfset varval="attributes." & varname>
					<cfif NOT IsDefined(varval)>
						<cfthrow type="cf_whm.InvalidAttribute" message="Required Attribute '#VarName#' is missing.">
					</cfif>
					<cfif Evaluate(varval) EQ "">
						<cfthrow type="cf_whm.InvalidAttribute" message="Required Attribute '#VarName#' must not be empty.">
					</cfif>
				</cfloop>
				<cfset whmquery="domain=" & attributes.domain>
			</cfcase>
			<!---/dumpzone--->
			<!---/DNS Functions--->
			<cfdefaultcase>
				<!---Invalid function requested--->
				<cfthrow type="cf_whm.TagError" message="The function '#attributes.function#' is not recognised.">
			</cfdefaultcase>
		</cfswitch>
		<!---/WHM Functions--->
		<!---send the command to the server--->
		<cfhttp url="#whmurl#?#whmquery#" method="get" timeout="#whmtimeout#" resolveurl="yes">
			<cfhttpparam type="header" name="Authorization" value="WHM #attributes.whmuser#:#whmhash#">
		</cfhttp>
		<cfif cfhttp.StatusCode NEQ "200 OK">
			<cfthrow type="cf_whm.TagError" message="cfhttp threw error: StatusCode: #cfhttp.StatusCode# Error Detail: #cfhttp.errorDetail#">
		</cfif>
		<cfscript>
			Response = StructNew();
			Response.Status = "COMPLETED";
			Response.StatusDetail = cfhttp.filecontent;
		</cfscript>
		<!---Error Handlers--->
		<cfcatch type="cf_whm.WHMError">
			<cfscript>
				Response = StructNew();
				Response.Status = "WHMERROR";
				Response.StatusDetail = CFCATCH.Message;
			</cfscript>
		</cfcatch>
		<cfcatch type="cf_whm.TagError">
			<cfscript>
				Response = StructNew();
				Response.Status = "TAGERROR";
				Response.StatusDetail = CFCATCH.Message;
			</cfscript>
		</cfcatch>
		<cfcatch type="cf_whm.InvalidAttribute">
			<cfscript>
				Response = StructNew();
				Response.Status = "CFERROR";
				Response.StatusDetail = CFCATCH.Message;
			</cfscript>
		</cfcatch>
		<cfcatch type="any">
			<cfscript>
				Response = StructNew();
				Response.Status = "TAGERROR";
				Response.StatusDetail = CFCATCH.Message;
			</cfscript>
		</cfcatch>
	</cftry>
	<cfset SetVariable("caller.#attributes.result#", Response )>
</cfprocessingdirective>
To call the tag you can use cfmodule or just save the above as whm.cfm in your custom tags directory. So for example to delete a dns zone you would do:

Code:
<cfmodule template="whm.cfm"
	whmhost="123.123.123.123:2086"
	whmuser="whm-user"
	whmhash="your-hash-key"
	RequestType="xml-api"
	function="killdns"
	domain="domainname.co.uk"
	result="whmresponse">

<cfdump var="#whmresponse#">
<cfif IsXML(whmresponse.statusdetail)>
	<cfdump var="#xmlparse(whmresponse.statusdetail)#">	
</cfif>
Hope this helps, it only does some basic dns functions so far; I might whack it on RiaForge at a later stage...