HttpClient, .NET, Access denied error exception. But works with cURL
Here is my F# code that raises the exception of Access denied:
Note: the periods on the left of some lines are to make the spacing show in the post. Indentation is important in F#. ================================================== I verified that I am using the correct username, token, and domain by using cURL: THIS WORKS: cURL --silent --header "Authorization: cpanel indinferaem:IAQY7WHZT9JUJ7U5CJ926N0W4LWO8N0F" "
open System
open System.Net.Http
open System.Net.Http.Headers
open System.Text
open System.Diagnostics
// global constants
let username = "indinferaem"
let token = "IAQY7WHZT9JUJ7U5CJ926N0W4LWO8N0F"
let domain = "assigned-email-manager.com"
let cPanelFunction = "list_pops"
let getEboxList (): unit = // function definition
let authHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{token}"))
let client = new HttpClient()
client.DefaultRequestHeaders.Authorization <- AuthenticationHeaderValue("Basic", authHeader)
let response = client.GetStringAsync($"https://{domain}:2083/execute/Email/{cPanelFunction}").Result // <<<<< Exception on this line
Debug.WriteLine(response)
()
Note: the periods on the left of some lines are to make the spacing show in the post. Indentation is important in F#. ================================================== I verified that I am using the correct username, token, and domain by using cURL: THIS WORKS: cURL --silent --header "Authorization: cpanel indinferaem:IAQY7WHZT9JUJ7U5CJ926N0W4LWO8N0F" "
-
Well, the problem with your Authorization:
header appears to be that you are passingBasic
as the method instead ofcpanel
if I'm reading your code correctly. Additionally, you are base64 encoding the user:token string, which is entirely unnecessary in this context. Fix that and it will probably get you going. Probably you want something more like the following:... let authHeader = $"{username}:{token}" let client = new HttpClient() client.DefaultRequestHeaders.Authorization <- AuthenticationHeaderValue("cpanel", authHeader) ...
That said, you probably should revoke that API token and regenerate something else while you are at it, as posting an API token on a public forum probably isn't the best idea. Hope this helps!0 -
cPRex, Thank you. Your answer is exactly on target. Changing to AuthenticationHeaderValue("cpanel", authHeader)
Fixed the problem. I agree with you about the token and have revoked it. Although I am currently using assigned-email-manager.com as a sandbox, someone with, shall we say, impure motives could, for example, wreak havoc and make it look like I am doing it. Here is the final code that works in case it helps someone else who is perhaps working in F#. Someone trying this code will have to replace the token with their own. And they will have to replace the domain name and username with those valid in their environment.open System.Net.Http open System.Net.Http.Headers open System.IO open System.Text open System.Diagnostics let getMailBoxes (domain: string) (username: string) (token: string): Async = async { [INDENT=2] // Create a URL for the cPanel API endpoint that lists the mailboxes. [INDENT=2] let url = $"https://{domain}:2083/execute/Email/list_pops" [INDENT=2] [INDENT=2] // Create a new HttpClient object. [INDENT=2] use httpClient = new HttpClient() [INDENT=2] [INDENT=2] // Set the Authorization header to the value of cpanel:{username}:{token}. [INDENT=2] httpClient.DefaultRequestHeaders.Authorization <- AuthenticationHeaderValue("cpanel", $"{username}:{token}") [INDENT=2] [INDENT=2] // Make a request to the cPanel API endpoint. [INDENT=2] // The GetAsync method is an asynchronous method returning a Task object. [INDENT=2] let! response = httpClient.GetAsync(url) |> Async.AwaitTask [INDENT=2] [INDENT=2] // Checks the status code. 200 means success. But ignore the result. ??? [INDENT=2] response.EnsureSuccessStatusCode() |> ignore [INDENT=2] [INDENT=2] // Read the response body as a stream. [INDENT=2] let! stream = response.Content.ReadAsStreamAsync() |> Async.AwaitTask [INDENT=2] [INDENT=2] // Create a new StreamReader object. [INDENT=2] use reader = new StreamReader(stream, Encoding.UTF8) [INDENT=2] [INDENT=2] // Read the contents of the stream as a string. [INDENT=2] let! content = reader.ReadToEndAsync() |> Async.AwaitTask [INDENT=2] return content [INDENT=2] } let domain = "assigned-email-manager.com" let username = "indinferaem" let token = "IAQY7WHZT9JUJ7U5CJ926N0W4LWO8N0F" let getEboxList (): unit = let result = getMailBoxes domain username token |> Async.RunSynchronously Debug.WriteLine(result) ()
0
Please sign in to leave a comment.
Comments
2 comments