I was reading a normal URL from my app, and it was working fine with the code:
string returnedTaskTResult = await new HttpClient().GetStringAsync(url);
then I used a new url, this time encrypted, and now is returning the exception:
System.InvalidOperationException: An invalid request URI was provided.
The request URI must either be an absolute URI or BaseAddress must be
set.
Why is this happening and how o fix it?
When you use GetStringAsync, you need to use a absolute URI. It sounds like your encrypted URI is relative. Try this...
var client = new HttpClient() { BaseAddress = new Uri("http://yourhosthere.com");
}
string returnedTaskTResult = await client.GetStringAsync(url);
Related
I am facing some trouble with the WebClient when using proxy, i.e. the code below does not work
WebClient webClient = WebClient.builder().baseUri("BASEURL").proxy(getProxy()).build();
Single<WebClientResponse> res = webClient.get().path("/MY/SUB/PATH").addHeader("Authorization", "Bearer " + MY_TOKEN).request();
WebClientResponse webClientRes = res.get();
String resContent = webClientRes.content().as(String.class).get();
public Proxy getProxy(){
return Proxy.builder().type(Proxy.ProxyType.HTTP).host(host).port(port).password("SECRET_PASSWORD".toCharArray()).username(username).build();
}
However the if we use Apache HttpClient the code works (working code below)
HttpHost proxy = new HttpHost(host, port);
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials(username, "SECRET_PASSWORD"));
HttpGet request = new HttpGet("BASEURL" + "/MY/SUB/PATH");
request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + MY_TOKEN);
CloseableHttpClient httpClient = HttpClients.custom().setProxy(proxy).setDefaultCredentialsProvider(credentialsProvider).build();
String resContent = EntityUtils.toString(httpClient.execute(request).getEntity());
could anyone let us know if we are overlooking something basic?
We are using helidon MP 2.5.2
When you set a proxy in WebClient, it will use absolute URI in the request because of changes made in https://github.com/helidon-io/helidon/issues/2302 and https://github.com/helidon-io/helidon/issues/3438. The use of absolute URI was implemented because of section 5.1.2 Request-URI in https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html which states:
The absoluteURI form is REQUIRED when the request is being made to a
proxy.
The problem is that some hosts have issue processing a request with absolute URI as they expect relative URI instead. I have encountered while working on issue https://github.com/helidon-io/helidon/issues/4644 where my testcase has a client that is connecting to KeyCloak as an OIDC server, and KeyCloak will return a 404 because it cannot handle the absoluteURI.
There is a special Webclient config property called relative-uris that you can use to force the request URI to use the relative form rather than absolute. So you can try adding config() in your WebClient.builder() and set that property like this:
.config(Config.create(ConfigSources.create(Map.of("relative-uris", "true")))
where Config needs to be imported as io.helidon.config.Config and ConfigSources as io.helidon.config.ConfigSources. As an alternative, you can also add something like this in your application.yaml:
force-relative-uris:
relative-uris: true
and add config() in the WebClient.builder() like this:
.config(config.get("force-relative-uris"))
where config is instantiated prior to WebClient.builder() like this:
Config config = Config.create();
In the upcoming Helidon v2.5.5 (and v3.0.3), there will be a new relativeUris(boolean relativeUris) in WebClient.builder() so that you don’t have to use config() as in my examples above, which is slightly cumbersome.
In my code using WebClient I can set the Authorization as:
var client = new System.Net.WebClient();
client.Headers.Add("Authorization", $"SharedKey {storage_account_name}:{signed_string}");
that works. But for HttpClient:
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse($"SharedKey {storage_account_name}:{signed_string}");
I get:
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<Error>
<Code>AuthenticationFailed</Code>
<Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:81dc1c79-901e-0053-5a16-637a77000000\nTime:2022-05-08T20:04:58.6215674Z</Message>
<AuthenticationErrorDetail>The MAC signature found in the HTTP request 'dpN6L5keMd9beEO/KLD65nuU7VMB6K5UTYtpBemPOpQ=' is not the same as any computed signature. Server used following string to sign: '*****'.</AuthenticationErrorDetail>
</Error>
Note: The ***** is replacing the actual string signed.
I also tried various combinations of explicitly creating the AuthenticationHeaderValue() - same problem. What do I need to do to get it to connect, like it does for WebClient?
Also posted to MSDN
I am looking into using MSAL and client credential flow, however, there is one thing I don't fully understand.
In the example provided by Microsoft:
https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/blob/master/daemon-console/Program.cs
The following code is used to get an access token:
var clientCredentials = new ClientCredential(_clientSecret);
var app = new ConfidentialClientApplication(_clientId, _authority, "https://daemon", clientCredentials, null, new TokenCache());
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = await app.AcquireTokenForClientAsync(scopes);
Whats with the redirectUri in this case?
I have tried different values as the redirectUri and it seems to work either way... but if I add a relative path or null it fails to obtain a token. What is this value supposed to be?
For a console application it makes little sense to listen on an URL, however, the documentation for ConfidentialClientApplication says that it is required.
To request access token with client credential flow , app will send HTTP POST token request to Azure AD's token endpoint with app's credential , AAD will return access token in response , redirect url is not need in this scenario . According to source code , the redirect url is not used also:
private async Task<AuthenticationResult> AcquireTokenForClientCommonAsync(IEnumerable<string> scopes, bool forceRefresh, ApiEvent.ApiIds apiId, bool sendCertificate)
{
Authority authority = Instance.Authority.CreateAuthority(ServiceBundle, Authority, ValidateAuthority);
AuthenticationRequestParameters parameters = CreateRequestParameters(authority, scopes, null,
AppTokenCache);
parameters.IsClientCredentialRequest = true;
parameters.SendCertificate = sendCertificate;
var handler = new ClientCredentialRequest(
ServiceBundle,
parameters,
apiId,
forceRefresh);
return await handler.RunAsync(CancellationToken.None).ConfigureAwait(false);
}
But you should provide a valid url when initializing the ConfidentialClientApplication at this point .
Trying to build a service that will grab info on a JIRA ticket based on an ID passed to it.
I'm calling the API to take the ID passed to the service, tack it onto the URL for the API and get the JSON object.
Problem is, it appears one must be logged on or registered on JIRA in order to use the API.
So if I use the code below to make my request, I get a 404 error, as I do on any browser which I've not used to log onto Jira
public string Get(string id)
{
string html = string.Empty;
string url = #"https://company.atlassian.net/rest/api/latest/issue/" + id;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
html = reader.ReadToEnd();
}
return html;
}
I can add credentials to the request like so
request.Credentials = new NetworkCredential("vinnie#company.com","mypassword");
but I've no idea exactly what needs sending. I've tried the email address with which I'm set up in Jira but that doesn't work.
I have a suspicion that Jira adds a cookie to my browser which it uses to validate after the initial config - is that so? If so, what can I add/include on my web request to get it to run?
Am I just wildly off on the right way to access it? Or are there changes that can be made to the Jira side to allow requests?
You have to encode your credentials in Base64 format first and then these credentials can be put into your request as shown below:
string mergedCredentials = string.Format("{0}:{1}", m_Username, m_Password);
byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(mergedCredentials);
string base64Credentials = Convert.ToBase64String(byteCredentials);
request.Headers.Add("Authorization", "Basic " + base64Credentials);
Hope you're able to solve your problem by this approach!
I'm trying to use the Asana restful API and I receive this error:
{"errors":[{"message":"Not Authorized"}]}
public static string GetProjects()
{
string url = "https://app.asana.com/api/1.0/projects/"; // Constants.BaseApiUrl + "projects";
var client = new RestClient(url);
System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
client.Authenticator = new HttpBasicAuthenticator(AsanaAPIKey.GetBase64(), "");
var req = new RestRequest(Method.GET);
RestResponse res =(RestResponse) client.Execute(req);
return res.Content;
}
public static bool CheckValidationResult(object sp,
X509Certificate cert,
X509Chain req,
System.Net.Security.SslPolicyErrors problem)
{
return true;
}
I've tried plain httpwebrequest/Httpwebresponse and it didn't work either so I tried the restsharp library and still the same problem.
Any ideas why this error is happening?
I don't know .NET but I see you're creating an HttpBasicAuthenticator and it looks like you're passing it a username/password pair. But you are passing it a base64-encoded version of the API key, which is wrong. The documentation on authentication states that when using an HTTP library you should pass the API key as the username, unchanged. You only need to manually base64-encode if you are constructing the full header manually.