Reputation: 109
I've looked everywhere and I just cant seem to figure this out:
After authenticating a cPanel session in C#, I scrape the security token from the url and try to plug it in to API calls, I get various errors (usually access denied or invalid token).
One thing to note is that I'm trying to do use the secure port in cPanel, which in this case is port 2083. However, when using hostgator hosting, I am redirected from my domain to a secure hostgator subdomain to log in (gatorXXXX.hostgator.com:2083/), and I'm wondering if this is throwing something off.
First I tried to use the following code, which I found on another stackoverflow post, but I modified it to:
Check if the cPanel login redirected me from my domain to the subdomain to login, and if so scrape that subdomain, then plug it in, run the code again, and get the session token.
public static string Connect(string url, string userName, string password, string userAgent, string postData, int timeOut)
{
string result = "";
// set a flag to determine if the cpanel page is different than the url
bool moved = false;
string newUrl = "";
try
{
// Create a request for the URL.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
if (userAgent == null)
userAgent = UserAgent;
request.UserAgent = userAgent;
request.Timeout = timeOut;
if (userName.Length > 0)
{
string authInfo = userName + ":" + password;
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
request.Headers["Authorization"] = "Basic " + authInfo;
request.AllowAutoRedirect = false;
}
if (postData.Length > 0)
{
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.CookieContainer = new CookieContainer();
// Create POST data and convert it to a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentLength = byteArray.Length;
using (Stream dataStream = request.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length);
}
}
// Get the response.
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
// Get the stream containing content returned by the server.
Stream dataStream = response.GetResponseStream();
response.Cookies = new CookieCollection();
// Open the stream using a StreamReader for easy access.
using (StreamReader reader = new StreamReader(dataStream))
{
result = string.Format("Server response:\n{0}\n{1}", response.StatusDescription, reader.ReadToEnd());
}
if (response.StatusDescription.ToLower().Contains("moved") && !response.Headers.ToString().Contains("/cpsess"))
{
newUrl = StringUtils.ExtractNoCase(result.ToLower(), "url=", "\">", 1);
moved = true;
}
else return result;
}
}
catch (Exception e)
{
result = string.Format("There was an error:\n{0}", e.Message);
}
// if the cpanel login is at a different location, Connect() with new url
if (moved == true)
{
result = Connect(newUrl, userName, password, null, postData, 8000);
}
return result;
}
Now after getting the security token, I've tried to plug it in to both the original url (https://mydomain.com:2083/cpsess12334455/xml-api/...) and the hostgator subdomain (https://gatorXXXX.hostgator.com:2083/cpsess/....) and both ways I get rejected.
So after fighting with that for days, I decided to try phalanger to perform this task, as most of the examples I've found for cPanel authentication are in php/curl.
So I use the following code:
function Authentication($hostname, $username, $password)
{
$download_url = "https://".$hostname.":2083/login/";
$curl = curl_init();
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($curl, CURLOPT_HEADER,0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER,1);
curl_setopt($curl, CURLOPT_URL, $download_url);
curl_setopt($curl, CURLOPT_POSTFIELDS, "user=".$username."&pass=".$password);
$result = curl_exec($curl);
curl_close($curl);
$parts = explode( 'URL=', $result);
$session_parts = explode( '/frontend/', $parts[1]);
$token = $session_parts[0];
$subdomain = "https://".$hostname.":2083" . $token . "/json-api/cpanel";
}
And then try to post something like the following (which is supposed to append a new subdomain to a domain):
$curl = curl_init();
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($curl, CURLOPT_HEADER,0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER,1);
curl_setopt($curl, CURLOPT_URL, $subdomain);
curl_setopt($curl, CURLOPT_POSTFIELDS, "user=username&cpanel_jsonapi_module=SubDomain&cpanel_jsonapi_func=addsubdomain&cpanel_jsonapi_version=2&domain=testingthis2&rootdomain=myrootdomain.com");
$result = curl_exec($curl);
curl_close($curl);
And while I get the security token, I always get the following result, even when copying the security token and running the API call from my browser:
{"cpanelresult":{"apiversion":"2","error":"Token denied","data":{"reason":"Token denied","result":"0"},"type":"text"}}
So I'm stumped. I would prefer to do this all in c# and not mess with phalanger as I'm not as well-versed in PHP as in C#, but at this point I would take either approach if one would work.
All I want to do is get the security token and plug it into an API call of my choice, and have cPanel accept my security token and process the API call.
Upvotes: 0
Views: 2475
Reputation: 542
this may be more of suggestion than an answer, because I don't know C# and your exact case.
From my experience I found that using the session token is not enough, you must also use it in the same session as you did the login in(stored, I think, in cookies). So, for example, if you login in one browser but try to use the session token to make an api call on another kind of browser, it will not work. Will work only if you try the api call in the same browser you made the login.
So, in C#, you must use some type of crawler/http client for login and the same to do the api calls.
Hope that helps.
Upvotes: 0