I am new to web based solutions. I am hitting a rest url using RestSharp library.
My code is as follows:
var cleint = new RestClient("http://REST_URL");
cleint.Authenticator = new HttpBasicAuthenticator("username", "password");
var request = new RestRequest();
request.Method = Method.GET;
request.Resource = "0.json";
IRestResponse response = cleint.Execute(request);
if (response != null && ((response.StatusCode == HttpStatusCode.OK) &&
(response.ResponseStatus == ResponseStatus.Completed)))
{
// var arr = JsonConvert.DeserializeObject<JArray> (response.Content);
}
The url returns a json file, when I hit it manually. But I want to use a C# console application to get the json file and save it to the disk. I am getting an unauthorized response when I run the above mentioned code:
response.ResponseStatus= "Unauthorized"
This is all it needed..
client.Authenticator = new NtlmAuthenticator();
So if your IIS settings have Windows Authentication set as enabled, this is what you are going to need, Http Basic authentication is not enough to by pass the server security
Related
I've developing an Angular web application using ASP.Net Core 3.1 for the API.
So far, I've written some integration unit tests using a Custom WebApplicationFactory to create the test server.
All tests use the HttpClient to make GETs and POSTs to the API running under the Custom WebApplicationFactory. Most of these tests initially perform a login to obtain a token to use for subsequent requests.
I'd like to add Two Factor Authentication to the application, but this will inevitably break any tests, as they aren't able to get hold of the six digit code which would be sent via email.
Here is what a test currently looks like, without MFA being implemented.
Is there a way that the test can be given the MFA code so that it can continue to perform tests?
Do I simply need to seed a user that does not have MFA enabled?
I actually want all users to have MFA enabled in production.
Many thanks
using Xunit;
using System.Threading.Tasks;
using MyCompany.ViewModels.Authentication;
using MyCompany.StaffPortal.Tests.Shared;
using StaffPortal;
using Newtonsoft.Json;
using MyCompany.ServiceA.ViewModels;
using System.Collections.Generic;
using System.Net.Http;
namespace MyCompany.Tests.StaffPortal.ServiceA
{
public class ExtensionsControllerTests : TestBase
{
public ExtensionsControllerTests(CustomWebApplicationFactory<Startup> factory) : base(factory)
{
}
[Fact]
public async Task Test_GetExtensions()
{
//This line creates a new "web browser" and uses the login details provided to obtain and set up the token so that we can request information about an account.
HttpClient httpClient = await CreateAuthenticatedHttpClient("abcltd1#MyCompany.com", "test", 1);
//Perform any work and get the information from the API
//Contact the API using the token so check that it works
var getExtensionsResponse = await httpClient.GetAsync("/api/ServiceA/extensions/GetExtensions");
//Check that the response was OK
Assert.True(getExtensionsResponse.StatusCode == System.Net.HttpStatusCode.OK, "GetExtensions did not return an OK result.");
//Get and Convert the Content we received into a List of ServiceAExtensionViewModel, as that is what GetExtensions sends back to the browser.
var getExtensionsResponseContent = await getExtensionsResponse.Content.ReadAsStringAsync();
List<ServiceAExtensionViewModel> extensionList = JsonConvert.DeserializeObject<List<ServiceAExtensionViewModel>>(getExtensionsResponseContent);
//Check the information received matches our expectations
Assert.True(extensionList.Count == 2);
Assert.True(extensionList[0].PropertyA == 123);
Assert.True(extensionList[0].PropertyB == 0161);
Assert.True(extensionList[0].PropertyC == true);
}
}
}
Here is the content's of CreateAuthenticatedHttpClient() for reference.
protected async Task<HttpClient> CreateAuthenticatedHttpClient(string username, string password, int companyAccountId)
{
var httpClient = _factory.CreateClient(
new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
//Create the Login information to send to the server
var loginInformation = new LoginRequestModel
{
Username = username,
Password = password,
ReturnUrl = ""
};
//Convert it into Json which the server will understand
var validLoginRequestJson = ConvertToJson(loginInformation);
//Send the Json Login information to the server, and put the response we receive into loginResponse
//In the code below, httpClient is like a web browser. You give it the
var loginResponse = await httpClient.PostAsync("/api/authenticate", validLoginRequestJson);
//Check the loginResponse was a CREATED response, which means that the token was made
Assert.True(loginResponse.StatusCode == System.Net.HttpStatusCode.Created, "New Token was not returned.");
//Check the response is identified as being in Json format
Assert.Equal("application/json; charset=utf-8", loginResponse.Content.Headers.ContentType.ToString());
//Next we have to convert the received Json information into whatever we are expecting.
//In this case, we are expecting a AuthenticationResponseViewModel (because that's what the API sends back to the person trying to log in)
//First we get hold of the Content (which is in Json format)
var responseJsonString = await loginResponse.Content.ReadAsStringAsync();
//Second we convert the Json back into a real AuthenticationResponseViewModel
AuthenticationResponseViewModel authenticationResponseViewModel = JsonConvert.DeserializeObject<AuthenticationResponseViewModel>(responseJsonString);
//Now we take the Token from AuthenticationResponseViewModel, and add it into the httpClient so that we can check the Token works.
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authenticationResponseViewModel.token);
httpClient.DefaultRequestHeaders.Add("CompanyId", companyAccountId.ToString());
return httpClient;
}
if I do a simple HTTP GET request with e.g. POSTMAN then in the response there's an element called 'entity_id'.
e.g. https://www.facebook.com/yourFacebookName
If however, I do the request from a simple C# app then the following code doesnt return the 'entity_id' element in the response and I cant figure out why?
Code from app:
string html = string.Empty;
string url = string.Format("https://www.facebook.com/{0}", "yourFBName");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
html = reader.ReadToEnd();
}
if (html.Contains("entity_id"))
{
//do some stuff
}
Anyone know why its dropping the 'entity_id' element, but returning it when hitting that url from POSTMAN etc?
I have implemented a REST service using Spring Integration.
When I try to access the service manually using main function, It is working fine.
I also tested the service using REST Client in Google Chrome and that worked. But the service is coming back with responseCode 404 on WebSphere server. So I am facing the issue when I deploy the code on higher environment.
URL u = new URL("http://localhost:8080/MyApplication/testRestService");
URLConnection uc = u.openConnection();
HttpURLConnection connection = (HttpURLConnection) uc;
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Accept","*/*");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStream out = connection.getOutputStream();
Writer wout = new OutputStreamWriter(out);
//helper function that gets a string from a dom Document
String input = jsonInput;
wout.write(input.getBytes());
wout.flush();
wout.close();
// Response
int responseCode = connection.getResponseCode();
Is is dependent on server, so its coming back with response code 404 ? Do we need any server side configuration ?
Any suggestion will be appreciated.
Why do you use different ContentType for URLConnection and for httpClient?
Show, please, your REST service config: 404 means Not found. Therefore you use (or don't) some options in request which makes it non-matching for the server's RequestMapping.
I tried with Apache HTTP Client and the code is working on WebSphere now. Still I am not able to find the reason why java.net.HttpURLConnection was not working on WebSphere.
Please find my updated code below :
DefaultHttpClient httpClient = null;
HttpPost postRequest = null;
StringEntity inputEntity = null;
HttpResponse response = null;
try{
//RETREIVE WEB SERVICE URL FROM DB
String callbackURL = "http://localhost:8080/MyApplication/testRestService";
httpClient = new DefaultHttpClient();
postRequest = new HttpPost(callbackURL);
String inputData = request.toString();
inputEntity = new StringEntity(inputData);
inputEntity.setContentType("application/x-www-form-urlencoded");
postRequest.setEntity(inputEntity);
response = httpClient.execute(postRequest);
if (response.getStatusLine().getStatusCode() != 201 && response.getStatusLine().getStatusCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "+ response.getStatusLine().getStatusCode());
}
//System.out.println("HTTP Response Code :"+response.getStatusLine().getStatusCode());
LOGGER.debug("HTTP Response Code :"+response.getStatusLine().getStatusCode());
httpClient.getConnectionManager().shutdown();
}catch(IOException ex){
ex.printStackTrace();
throw ex;
}finally{
httpClient.getConnectionManager().shutdown();
httpClient = null;
postRequest = null;
inputEntity = null;
response = null;
}
I am using SAML2 Bearer assertion profile to obtain OAuth Tokens form WSO2 API Manager. I have two client applications. In the OAuth Token Revoking process I am using following code,
public static boolean revokeToken(Token token) throws IOException {
//Create connection to the Token endpoint of API manger
URL url = new URL(Config.apiMangerOAuthRevokeURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
String userCredentials = Config.apiMangerClientID+":"+ Config.apiMangerClientSecret;
String basicAuth = "Basic " + new String(Base64.encodeBytes(userCredentials.getBytes()));
basicAuth = basicAuth.replaceAll("\\r|\\n", "");
// Set the consumer-key and Consumer-secret
connection.setRequestProperty("Authorization", basicAuth);
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Send request
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.writeBytes("token="+token.getAccess_token());
wr.flush();
wr.close();
//Get Response
InputStream iss = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(iss));
String line;
StringBuffer responseString = new StringBuffer();
while ((line = rd.readLine()) != null) {
responseString.append(line);
responseString.append('\r');
}
rd.close();
System.out.println("Revoking Token Mobile-"+token.getAccess_token());
System.out.println("Revoking Response Mobile -"+responseString.toString());
return true
;
}
One client application do the revoking process OK. I tried to invoke API using CURL after revoking, it fails as expected. But the other client application which use same above logic to revoke tokens return well. But the token is valid after revoking. I can use CURL to query the API. What has gone wrong here?
API Manager has caching enabled by default and is set to 15 min. Try disabling it.
I am working in a Windows Phone 8 PCL project. I am using a 3rd party REST API and I need to use a few HttpOnly cookies originated by the API. It seems like getting/accessing the HttpOnly cookies from HttpClientHandler's CookieContainer is not possible unless you use reflection or some other backdoor.
I need to get these cookies and send them in subsequent requests otherwise I am not going to be able to work with this API - how can I accomplish this? Here is what my current request code looks like:
Thanks in advance.
//Some request
HttpRequestMessage request = new HttpRequestMessage();
HttpClientHandler handler = new HttpClientHandler();
//Cycle through the cookie store and add existing cookies for the susbsequent request
foreach (KeyValuePair<string, Cookie> cookie in CookieManager.Instance.Cookies)
{
handler.CookieContainer.Add(request.RequestUri, new Cookie(cookie.Value.Name, cookie.Value.Value));
}
//Send the request asynchronously
HttpResponseMessage response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
//Parse all returned cookies and place in cookie store
foreach (Cookie clientcookie in handler.CookieContainer.GetCookies(request.RequestUri))
{
if (!CookieManager.Instance.Cookies.ContainsKey(clientcookie.Name))
CookieManager.Instance.Cookies.Add(clientcookie.Name, clientcookie);
else
CookieManager.Instance.Cookies[clientcookie.Name] = clientcookie;
}
HttpClient httpClient = new HttpClient(handler);
The HttpOnly cookie is inside the CookieContainer, it's only that is not exposed. If you set the same instance of that CookieContainer to the next request it will set the hidden cookie there (as long as the request is made to the same site the cookie specifies).
That solution will work until you need to serialize and deserialize the CookieContainer because you are restoring state. Once you do that you lose the HttpOnly cookies hidden inside the CookieContainer. So, a more permanent solution would be using Sockets directly for that request, read the raw request as a string, extract the cookie and set it to the next requests. Here's the code for using Sockets in Windows Phone 8:
public async Task<string> Send(Uri requestUri, string request)
{
var socket = new StreamSocket();
var hostname = new HostName(requestUri.Host);
await socket.ConnectAsync(hostname, requestUri.Port.ToString());
var writer = new DataWriter(socket.OutputStream);
writer.WriteString(request);
await writer.StoreAsync();
var reader = new DataReader(socket.InputStream)
{
InputStreamOptions = InputStreamOptions.Partial
};
var count = await reader.LoadAsync(512);
if (count > 0)
return reader.ReadString(count);
return null;
}
There is also a second possibility - to manually go through response headers, grab and then parse Set-Cookie headers using a bunch of custom code.
It looks something like that, when you are going to match and save a single PHPSESSID cookie (assume LatestResponse is your HttpResponseMessage containing website response):
if (LatestResponse.Headers.ToString().IndexOf("Set-Cookie:") != -1) try
{
string sid = LatestResponse.Headers.ToString();
sid = sid.Substring(sid.IndexOf("Set-Cookie:"), 128);
if (sid.IndexOf("PHPSESSID=") != -1)
{
settings.Values["SessionID"] = SessionID = sid.Substring(sid.IndexOf("PHPSESSID=") + 10, sid.IndexOf(';') - sid.IndexOf("PHPSESSID=") - 10);
handler.CookieContainer.Add(new Uri("http://example.com", UriKind.Absolute), new System.Net.Cookie("PHPSESSID", SessionID));
}
} catch (Exception e) {
// your exception handling
}
Note this code inserts the cookie to CookieContainer for that object's life unless manually deleted. If you want to include it in a new object, just pull the right setting value and add it to your new container.