Prevent RestSharp changing https to http - c#-4.0

I have a very simple piece of code using v130 of RestSharp. The code itself compiles fine and returns values from the server - the problem is they're not the ones I'm after.
Code
private void startTest()
{
string email = "bob2#example.com";
string password = "password";
doRestSharpWebRequest(email, password);
}
private void doRestSharpWebRequest(email, password)
{
var restClient = new RestClient();
restClient.BaseUrl = "https://mytestserver.com/api";
restClient.Authenticator = new SimpleAuthenticator("email", email, "password", password);
var restRequest = new RestRequest("token", Method.GET);
restRequest.AddHeader("Accepts", "application/json;version=1");
restRequest.AddHeader("Authorization", "apikey zyzyz");
restRequest.RequestFormat = DataFormat.Json;
IRestResponse<userlogin> response = restClient.Execute<userlogin>(restRequest);
}
where userlogin is just a class to deserialize to.
When I run the code, I'm presented with the following error
Message = No HTTP resource was found that matches the request URI 'http://mytestserver.com/api/token?Email=bob%40example.com&password=password'.
Two things are apparent, the # has been changed to %40 which should cause a problem and the http has been changed to https.
Can restsharp be told not to convert from https and http?

Related

REST Api is not returning expected data

I wrote an Auth API where it should retrieve the details from my user, but I'm getting error 404 instead. All my users are stored in an Azure Storage Account, and I was using the TableClient class to handle with my table. However I am not able to go any further when I started to do this Auth. I spent over one week only on this function, and I got no progress on this, here is my code:
[FunctionName(nameof(Auth))]
public static async Task<IActionResult> Auth(
[HttpTrigger(AuthorizationLevel.Admin, "POST", Route = "auth")] HttpRequest req,
[Table("User", Connection = "AzureWebJobsStorage")] TableClient tdClient,
ILogger log)
{
string url = String.Format("http://localhost:7235/api/");
HttpMessageHandler handler = new HttpClientHandler()
{
};
var httpClient = new HttpClient(handler)
{
BaseAddress = new Uri(url),
Timeout = new TimeSpan(0, 2, 0)
};
httpClient.DefaultRequestHeaders.Add("ContentType", "application/json");
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes("roy.mitchel#somecompany.com:pass1234");
string val = System.Convert.ToBase64String(plainTextBytes);
httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + val);
HttpResponseMessage response = httpClient.GetAsync(url).Result;
return new OkObjectResult(response);
}
How can auth my user using this class? Iam doing on the right way?
Thanks.
Debugging any API issues by looking at just the code, is (as you have discovered) a horribly painful process.
I'd strongly recommend using a MITM proxy (like burp) to get visibility of exactly what is sent to, and received from the API. By using this approach, it generally becomes really obvious what is wrong.
If you can't use this approach, then enable logging for the raw HTTP request and response, as outlined in this guide.

JAX-WS Authentication SoapUI vs. Client application

I need to create an SOAP client with JAX-WS on JBoss.
The Problem is I cannot get past the authentication.
I have a test implemented in SoapUI which works when I set the request properties username and password
With the following code
URL kbaURL = new URL("http://...");
IkfzService ikfzService = new IkfzService(kbaURL);
IkfzPortType ikfzPortType = ikfzService.getIkfzSOAP();
Map<String, Object> requestContext = ((BindingProvider)ikfzPortType).getRequestContext();
requestContext.put(BindingProvider.USERNAME_PROPERTY, "...");
requestContext.put(BindingProvider.PASSWORD_PROPERTY, "...");
Where URL, username und password are the same like in SOAPUI I am getting
javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException:
Failed to create service.
...
Caused by: javax.wsdl.WSDLException: WSDLException: faultCode=PARSER_ERROR:
Problem parsing 'http://..'.: java.io.IOException: Server returned HTTP response code:
401 for URL: http://..
What am I missing?
This should be a basic example of what you're trying to accomplish - let me know if you need more help or clarification
//the WSDL/webservice endpoint
private static final String WSDL_URL = "http://localhost:8080/MyWebService/MyWebService?wsdl";
URL url = new URL(WSDL_URL);
QName qname = new QName("http://ws.mycompany.com/", MyWebServiceImpl");
Service theWSService = Service.create(url, qname);
//returns the interface for MyWebServiceImpl
TheWSServiceIF port = theWSService.getPort(TheWSServiceIF.class);
//Setup Security
Map<String, Object> requestContext = ((BindingProvider)port).getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, WS_URL);
Map<String, List<String>> requestHeaders = new HashMap<String, List<String>>();
requestHeaders.put("Username", Collections.singletonList("myUserName"));
requestHeaders.put("Password", Collections.singletonList("myPasword"));
requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
/**********************************************************************/
//actually call the web service method, print results
System.out.println(port.getMyWebServiceData());

ADAL authentication without dialog box prompt

I have a console application registered in Azure AD that connects to CRM Online (configured using these steps). It queries the Web API.
The application needs to run with no user interaction... but unfortunately the call to AcquireTokenSilentAsync always fails and only AcquireTokenAsync works. This makes a user login dialog appear which fails the user interaction requirement!
Is there any way to prevent this prompt, either by saving the login somewhere on the client machine (which hasn't worked so far) or perhaps using a certificate (but how do you do this?) or something else?
I'm using the ADAL for .NET v3.10.305110106 release. The following code is used to authenticate:
private static async Task PerformOnlineAuthentication()
{
_authInfo = new AuthInfo(); // This is just a simple class of parameters
Console.Write("URL (include /api/data/v8.x): ");
var url = Console.ReadLine();
BaseUri = new Uri(url);
var absoluteUri = BaseUri.AbsoluteUri;
_authInfo.Resource = absoluteUri;
Console.Write("ClientId: ");
var clientId = Console.ReadLine();
_authInfo.ClientId = clientId;
Console.Write("RedirectUri: ");
var redirectUri = Console.ReadLine();
_authInfo.RedirectUri = new Uri(redirectUri);
var authResourceUrl = new Uri($"{_authInfo.Resource}/api/data/");
var authenticationParameters = await AuthenticationParameters.CreateFromResourceUrlAsync(authResourceUrl);
_authInfo.AuthorityUrl = authenticationParameters.Authority;
_authInfo.Resource = authenticationParameters.Resource;
_authInfo.Context = new AuthenticationContext(_authInfo.AuthorityUrl, false);
}
private static async Task RefreshAccessToken()
{
if (!IsCrmOnline())
return;
Console.WriteLine($"Acquiring token from: {_authInfo.Resource}");
AuthenticationResult authResult;
try
{
authResult = await _authInfo.Context.AcquireTokenSilentAsync(_authInfo.Resource, _authInfo.ClientId);
}
catch (AdalSilentTokenAcquisitionException astae)
{
Console.WriteLine(astae.Message);
authResult = await _authInfo.Context.AcquireTokenAsync(_authInfo.Resource, _authInfo.ClientId, _authInfo.RedirectUri, new PlatformParameters(PromptBehavior.RefreshSession));
}
HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
}
Thanks to #aravind who pointed out the active-directory-dotnet-native-headless sample.
The sample contains a FileCache class which inherits from Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache. That class manages caching of the credentials to an encrypted file on disk. This means that there is only one prompt on first run and after that the credentials are locally stored.
The final pieces of the puzzle are:
Calling a different constructor signature to initialize AuthenticationContext with the FileCache:
_authInfo.Context = new AuthenticationContext(
_authInfo.AuthorityUrl, false, new FileCache());
Obtaining credentials from the user into a Microsoft.IdentityModel.Clients.ActiveDirectory.UserPasswordCredential object (see the TextualPrompt() method in the sample)
Passing the credentials to a different method signature for AcquireTokenAsync():
authResult = await _authInfo.Context.AcquireTokenAsync(
_authInfo.Resource, _authInfo.ClientId, userCredential);
If "application needs to run with no user interaction" use ClientCredential flow eg:
public static string GetAccessTokenUsingClientCredentialFlow(Credential cred) {
AuthenticationContext ac = new AuthenticationContext(cred.Authority);
AuthenticationResult r = ac.AcquireTokenAsync(cred.ResourceId, new ClientCredential(cred.ClientId, cred.ClientSecret)).Result;
return r.AccessToken;
}

ServiceStack - Switch off Snapshot

I've followed instructions on how creating a ServiceStack here at:
https://github.com/ServiceStack/ServiceStack/wiki/Create-your-first-webservice
I'm sure I have followed it to the letter, but as soon as I run the web application. I get a 'Snapshot' view of my response. I understand this happens when I don't have a default view/webpage. I set up the project as a ASP.net website, not a ASP.net MVC website. Could that be the problem?
I also wrote a test console application with the following C# code. It got the response as a HTML webpage rather than as a plain string e.g. "Hello, John".
static void sendHello()
{
string contents = "john";
string url = "http://localhost:51450/hello/";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentLength = contents.Length;
request.ContentType = "application/x-www-form-urlencoded";
// SEND TO WEBSERVICE
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(contents);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string result = string.Empty;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
Console.WriteLine(result);
}
How can I switch off the 'snapshot' view? What am I doing wrong?
The browser is requesting html so ServiceStack is returning the html snapshot.
There are a couple of ways to stop the snapshot view:
First is to use the ServiceClient classes provided by servicestack. These also have the advantage of doing automatic routing and strongly typing the response DTOs.
Next way would be to set the Accept header of the request to something like application/json or application/xml which would serialize the response into json or xml respectively. This is what the ServiceClients do internally
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/json";
...
Another method would be to add a query string parameter called format and set it to json or xml
string url = "http://localhost:51450/hello/?format=json";
Putting the specific format requesting is the practical way to do this
string url = "http://localhost:51450/hello/?format=json";
I suggest simply deleting this feature.
public override void Configure(Container container)
{
//...
this.Plugins.RemoveAll(p => p is ServiceStack.Formats.HtmlFormat);
//...
}
Now all requests with the Content-Type=text/html will be ignored.

Is there a more elegant way to build URIs in ServiceStack?

I'm building a Request/Acknowledge/Poll style REST service with NServiceBus underneath to manage queue processing. I want to give the client a URI to poll for updates.
Therefore I want to return a location header element in my web service as part of the acknowledgement. I can see that it is possible to do this:
return new HttpResult(response, HttpStatusCode.Accepted)
{
Location = base.Request.AbsoluteUri.CombineWith(response.Reference)
}
But for a Url such as: http://localhost:54567/approvals/?message=test, which creates a new message (I know I should probably just use a POST), the location will be returned as: http://localhost:54567/approvals/?message=test/8f0ab1c1a2ca46f8a98b75330fd3ac5c.
The ServiceStack request doesn't expose the Uri fragments, only the AbsouteUri. This means that I need to access the original request. I want this to work regardless of whether this is running in IIS or in a self hosted process. The closest I can come up with is the following, but it seems very clunky:
var reference = Guid.NewGuid().ToString("N");
var response = new ApprovalResponse { Reference = reference };
var httpRequest = ((System.Web.HttpRequest)base.Request.OriginalRequest).Url;
var baseUri = new Uri(String.Concat(httpRequest.Scheme, Uri.SchemeDelimiter, httpRequest.Host, ":", httpRequest.Port));
var uri = new Uri(baseUri, string.Format("/approvals/{0}", reference));
return new HttpResult(response, HttpStatusCode.Accepted)
{
Location = uri.ToString()
};
This now returns: http://localhost:55847/approvals/8f0ab1c1a2ca46f8a98b75330fd3ac5c
Any suggestions? Does this work regardless of how ServiceStack is hosted? I'm a little scared of the System.Web.HttpRequest casting in a self hosted process. Is this code safe?
Reverse Routing
If you're trying to build urls for ServiceStack services you can use the RequestDto.ToGetUrl() and RequestDto.ToAbsoluteUri() to build relative and absolute urls as seen in this earlier question on Reverse Routing. e.g:
[Route("/reqstars/search", "GET")]
[Route("/reqstars/aged/{Age}")]
public class SearchReqstars : IReturn<ReqstarsResponse>
{
public int? Age { get; set; }
}
var relativeUrl = new SearchReqstars { Age = 20 }.ToUrl("GET");
var absoluteUrl = HostContext.Config.WebHostUrl.CombineWith(relativeUrl);
relativeUrl.Print(); //= /reqstars/aged/20
absoluteUrl.Print(); //= http://www.myhost.com/reqstars/aged/20
For creating Urls for other 3rd Party APIs look at the Http Utils wiki for example extension methods that can help, e.g:
var url ="http://api.twitter.com/user_timeline.json?screen_name={0}".Fmt(name);
if (sinceId != null)
url = url.AddQueryParam("since_id", sinceId);
if (maxId != null)
url = url.AddQueryParam("max_id", maxId);
var tweets = url.GetJsonFromUrl()
.FromJson<List<Tweet>>();
You can also use the QueryStringSerializer to serialize a number of different collection types, e.g:
//Typed POCO
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
new Login { Username="mythz", Password="password" });
//Anonymous type
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
new { Username="mythz", Password="password" });
//string Dictionary
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
new Dictionary<string,string> {{"Username","mythz"}, {"Password","password"}});
You can also serialize the built-in NameValueCollection.ToFormUrlEncoded() extension, e.g:
var url = "http://example.org/login?" + new NameValueCollection {
{"Username","mythz"}, {"Password","password"} }.ToFormUrlEncoded();

Resources