Server Side Code
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
try
{
string clientId;
string clientSecret, deviceId;
string appId = context.Parameters["applicationId"];//renamed from applicationName
string version = context.Parameters["version"];
deviceId = context.Parameters["deviceId"];//renamed from applicationName
context.OwinContext.Set("appId", appId);
ApiAppClient client;
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
{
context.TryGetFormCredentials(out clientId, out clientSecret);
}
if (string.IsNullOrWhiteSpace(clientId))
{
context.TryGetFormCredentials(out clientId, out clientSecret);
}
if (string.IsNullOrWhiteSpace(clientId))
{
var query = context.Parameters.Where(x => x.Key == "client_id");
if (query.Any())
{
clientId = query.FirstOrDefault().Value?[0];
}
}
if (string.IsNullOrWhiteSpace(clientId))
{
//Remove the comments from the below line context.SetError, and invalidate context
//if you want to force sending clientId/secrects once obtain access tokens.
//context.Validated();
context.SetError($"Missing ClientId.");
////context.Rejected();
return;
}
Client Side Code
POST https://example.com/token HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Host: example.com
Content-Length: 258
client_id=xxxxxxxxxxxxxxxxxxxxxx&client_secret=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz&applicationId=aaaaaaaaaaaaaaaaaaaaaaaa&username=me&password=somthing&grant_type=password&deviceId=5545555&version=3.2.1.89
I have a strange case for above OAuth process ClientId is null as well as Parameters is empty.
The above code works fine on all of our developer machines.
Compiled Version of Web API also works if hosted in IIS on Developer Machine.
But When I try to host Web API on my remote server it always gives error "Missing ClientId".
It uses to work perfectly on the same server before upgrading NuGet packages.
Microsoft.Owin.Security.OAuth 3.0.1.0 upgraded to 3.1.0.0
Microsoft.Owin.Security 3.0.1.0 upgraded to 3.1.0.0
And All Unity Packages
Related
How to connect NPHIES FHIR OBB(Testing) Server inorder to submit eligibility/preauthorization/claims and soon.
Lot of companies built tools to work with FHIR SERVERS.
Firely - .Net Framework / .Net Core - link
HAPI- JAVA - link
Those who were working with Firely - .NET SDK, click this link to view the documentation.
In order to send the request to NPHIES OBB SERVER, you need to pass Username, password and content-type
username: xxxxx
password: yyyyy
content-type: application/fhir+json
Check the below code to send a request to NPHIES - OBB FHIR Server
using (var handler = new HttpClientEventHandler())
{
handler.OnBeforeRequest += (sender, e) =>
{
e.RawRequest.Content.Headers.ContentType.CharSet = "";
e.RawRequest.Content.Headers.Remove("Content-Type"); // "{application/json; charset=utf-8}"
e.RawRequest.Content.Headers.Add("Content-Type", "application/fhir+json");
e.RawRequest.Content.Headers.Add("Username", xxxx);
e.RawRequest.Content.Headers.Add("Password", yyyy);
};
handler.OnAfterResponse += (sender, e) =>
{
};
using (FhirClient fhirClient = new FhirClient(
nphiesServerURL, new FhirClientSettings() { PreferredFormat = ResourceFormat.Json},handler))
{
Bundle responseBundle = fhirClient.Transaction(bundle);
}
}
I'm unable to perform an HTTP Post with an app running in an Android Emulator.
{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content:
System.Net.Http.HttpConnection+HttpConnectionResponseContent, Headers:
{ Server: Microsoft-HTTPAPI/2.0 Date: Wed, 23 Oct 2019 00:58:01
GMT Connection: close Forwarded: host=XXX.XXX.X.XX:XXXXX;
proto=https Content-Type: text/html; charset=us-ascii
Content-Length: 374 }}
Setup:
I'm using an IP address generated by Conveyor by Keyoti
I installed a security certificate on the emulator required by Conveyor by Keyoti
I swapped out Microsoft.AspNetCore.Mvc.HttpPost attribute with System.Web.Http.HttpPost
Emulator:
Successful: HTTP Get
Failed: HTTP Post
Integration Test:
Successful: HTTP Post (using same endpoint)
Code:
I wrote an automated test that calls the same HTTP Post implementation.
Because I executed the same code successfully on my laptop via an automated test, I don't think the actual code is the issue:
open Microsoft.AspNetCore.Mvc
open Newtonsoft.Json
[<ApiController>]
[<Route("api/[controller]")>]
type RegisterController () =
inherit ControllerBase()
[<System.Web.Http.HttpPost>]
member x.Post([<FromBody>] json:string) =
...
Summary:
In conclusion, I have isolated the environment to the Android Emulator and not my laptop. Hence, the emulator can successfully trigger an HTTP Get. However, it fails to perform a HTTP Post even though my laptop device can do both.
UPDATE:
I applied guidance from this Xamarin Android ASP.Net Core WebAPI document.
Specifically, I installed another security certificate on the Android emulator.
I was then able to observe an HTTP Get on the Android Emulator.
However, I continue to get an error for HTTP Post.
OperationCanceledException
Physical Device:
If I run the app from a physical android device I observe the following:
{StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1, Content: System.Net.Http.HttpConnection+HttpConnectionResponseContent, Headers:
{
Date: Wed, 23 Oct 2019 13:33:20 GMT
Server: Kestrel
Transfer-Encoding: chunked
Forwarded: host=xxx.xxx.x.xx:xxxxx; proto=https
Content-Type: text/plain
}}
New Update:
I disabled debugging on just my code on the server implementation and discovered the following exception:
Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: 'Bad chunk size data.'
Any suggestions?
this might not be a direct answer to your question, but i would like to suggest
localtunnel. a very easy way to temporarily expose your local api so that you can test it either on emulator or even physical device. Have used this alot my self, as it is very convenient to just type a single line in terminal to start it.
The following reference solved my issue.
Infrastructure:
type GlobalHttpClient private () =
static let mutable (httpClient:System.Net.Http.HttpClient) = null
static member val Instance = httpClient with get,set
Xamarin.Android project:
using Android.Http;
using Android.Net;
using Javax.Net.Ssl;
using System.Net.Http;
using Xamarin.Android.Net;
using Xamarin.Forms;
using WebGatewaySupport;
[assembly: Dependency(typeof(HTTPClientHandlerCreationService_Android))]
namespace Android.Http
{
public class HTTPClientHandlerCreationService_Android : IHTTPClientHandlerCreationService
{
public HttpClientHandler GetInsecureHandler()
{
return new IgnoreSSLClientHandler();
}
}
internal class IgnoreSSLClientHandler : AndroidClientHandler
{
protected override SSLSocketFactory ConfigureCustomSSLSocketFactory(HttpsURLConnection connection)
{
return SSLCertificateSocketFactory.GetInsecure(1000, null);
}
protected override IHostnameVerifier GetSSLHostnameVerifier(HttpsURLConnection connection)
{
return new IgnoreSSLHostnameVerifier();
}
}
internal class IgnoreSSLHostnameVerifier : Java.Lang.Object, IHostnameVerifier
{
public bool Verify(string hostname, ISSLSession session)
{
return true;
}
}
}
Xamarin.Forms App:
switch (Device.RuntimePlatform)
{
case Device.Android:
GlobalHttpClient.Instance = new HttpClient(DependencyService.Get<IHTTPClientHandlerCreationService>().GetInsecureHandler());
break;
default:
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
GlobalHttpClient.Instance = new HttpClient(new HttpClientHandler());
break;
}
Client Gateway:
let postTo (baseAddress:string) (resource:string) (payload:Object) =
GlobalHttpClient.Instance.BaseAddress <- Uri(baseAddress)
let encoded = Uri.EscapeUriString(resource)
let result = GlobalHttpClient.Instance.PostAsJsonAsync(encoded, payload) |> toResult
result
Looks like you have a .NET Core Api. .NET Core does not have System.Web in Asp.NET. The HttpPost attribute and HttpGet attributes should come from Microsoft.AspNetCore.Mvc namespace which you have open.
Also since you are using the ApiController attribute model binding will just work as long as you bind to a model and not just a json string.
Create a model that you want the json to bind to and use that type for your parameter on Post and remove the FromBody attribute. Also if you do that you probably don't need newtonsoft.json.
open Microsoft.AspNetCore.Mvc
[<ApiController>]
[<Route("api/[controller]")>]
type RegisterController () =
inherit ControllerBase()
[<HttpPost>]
member x.Post(thing:TypeOfThing) =
This is going to be a long question..
Our company has to follow PCI Standards, so a while back we had to ensure all our Servers were TLS1.2 compliant. As a result we implemented TLS as explained here in our Xamarin Forms app. But we noticed issues in Android versions less then Api 22. So we implemented a dependency service for fetching the HTTPClient and if the Api versions were less than 22 we implemented a custom ssl socket factory, here's the example.
Everything was fine till a few weeks back there was a decision to upgrade the servers to Windows 2016 on the dev environment. We've redeployed our Web Api to the server and ever since then, the api is inaccessible from a few devices. The problem we've faced is in Samsung Galaxy S4(Android 4.4) and Nexus 5(Android 5.1.1). We've tried testing the app on a Samsung Galaxy A7(Android 6) and it works okay. iOS is also fine.
This is the error we recieve on the S4 and Nexus 5
StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content:
System.Net.Http.StreamContent, Headers: { Date: Wed, 20 Sep 2017
04:00:09 GMT Server: Microsoft-IIS/10.0 X-Android-Received-Millis:
1505880010792 X-Android-Response-Source: NETWORK 404
X-Android-Selected-Transport: http/1.1 X-Android-Sent-Millis:
1505880010781 X-Powered-By: ASP.NET Content-Length: 1245 Content-Type:
text/html
Here's the signature of the Web Api
[HttpPost("GetMinimumVersion")]
public GetMinimumVersionResponse GetMinimumVersion([FromBody] GetMinimumVersionRequest value)
And this is the code we use to make a post request
using (_httpclient = _deviceInfo.GetHttpClient())
{
_httpclient.MaxResponseContentBufferSize = 256000;
_httpclient.BaseAddress = new Uri(BaseAddress);
_httpclient.Timeout = timeout > 0 ? TimeSpan.FromSeconds(timeout) : TimeSpan.FromSeconds(60000);
Insights.Track("ApiUrlCalled", new Dictionary<string, string> { { "Api URL", url } });
var jsonOut = new StringContent(JsonConvert.SerializeObject(body, new IsoDateTimeConverter()));
jsonOut.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = await _httpclient.PostAsync(url, jsonOut);
switch (response.StatusCode)
{
case HttpStatusCode.OK:
var content = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<T>(content);
ReceiveNotificationDateTime(result);
return result;
default:
var result1 = new T { StatusID = (int)SystemStatusOutcomes.Failed, StatusMessage = response.ToString() };
ReceiveNotificationDateTime(result1);
return result1;
}
}
It's worth noting that the app when talking to the production api works fine on all devices. And we're also able to make post requests to the dev api via Postman.
After some digging and scratching, I found out that the ciphers used on production and dev were different.
Here's the cipher used on Prod
and here's the one used on dev.
I had a look at the SSL Ciphers Android supports here. And it looks like the ciper suite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 is supported in Android Api version 20+. This makes sense that it wont work on Android 4.4. But why would we get this error on Nexus 5? Any pointers?
Also is there any workaround to get this cipher enabled on Android 4.4?
I'm using Visual Studio 2015 for our performance testing. I'm using a web test to make a call to an API endpoint. Using fiddler and HTTPRequester I can connect to the API with no problem. When I use the webtest I receive a 401 unauthorized. The difference between the webtest and everything else is the webtest is using Authorization: Negotiate instead of Authorization: Basic.
How, in Visual Studio 2015 can I force the Authorization to Basic instead of negotiate?
Here is the header as the webtest currently creates it:
POST /Foo/api.asp?$api=FooBarAPI HTTP/1.1
Accept : application/xml
User-Agent : Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Accept-Language : en-US
Accept-Encoding : GZIP
Content-Type : application/xml
Authorization : Negotiate (Base64 Encoded Login Information)
Host : Foo.Bar.net
Content-Length : 0
If this is a duplicate I apologize. I've been looking all day for information on this and I have found nothing that helps.
Basic authentication is done by adding the appropriate header field to the requests. You can use a plugin based on the following code.
public string UserName { get; set; }
public string Password { get; set; }
public override void PreRequest(object sender, PreRequestEventArgs e)
{
e.Request.Headers.Add("Authorization", "Basic " + GetEncodedAuthorisation(UserName, Password));
}
private string GetEncodedAuthorisation(string userName, string password)
{
return Encode8BitStringInBase64(userName + ":" + password);
}
private string Encode8BitStringInBase64(string source)
{
byte[] outBytes = new byte[source.Length];
for (int ix = 0; ix < source.Length; ix++)
{
char ch = source[ix];
outBytes[ix] = (byte)(((int)ch) & 0xFF);
}
return Convert.ToBase64String(outBytes);
}
See also this page.
A comment says "I have hundreds of performance tests I have to modify now". The ".webtest" file is just XML. You can try making the above code into a WebTestPlugin, ie one that is called for every request in the test. Then manually add that to one test and see exactly what changes are made to the XML of that test. It should then be a simple scripting (or editing) task to modify all the files.
Other option is - you can grab basic auth token using Postman and pass it along in the headers. It worked for me.
I have a Play! framework Heroku project that has three deployments. One for running my dev machine, one for beta on Heroku, and one for production on Heroku. Their http and https urls are as follows:
DEV BETA PRODUCTION
HTTP URL | http://localhost:9000 http://domain-beta.herokuapps.com http://www.domain.com
HTTPS URL | https://localhost:9443 https://domain-beta.herokuapps.com https://secure.domain.com
HTTPS Type | My cert Piggyback (using Heroku's cert) Hostname-based SSL (using my cert)
I also have a class HttpsRequired that has methods for requiring HTTPS, and for redirecting back to HTTP (thanks to this post for the help).
public class HttpsRequired extends Controller {
/** Called before every request to ensure that HTTPS is used. */
#Before
public static void redirectToHttps() {
//if it's not secure, but Heroku has already done the SSL processing then it might actually be secure after all
if (!request.secure && request.headers.get("x-forwarded-proto") != null) {
request.secure = request.headers.get("x-forwarded-proto").values.contains("https");
}
//redirect if it's not secure
if (!request.secure) {
String url = redirectHostHttps() + request.url;
System.out.println("Redirecting to secure: " + url);
redirect(url);
}
}
/** Renames the host to be https://, handles both Heroku and local testing. */
#Util
public static String redirectHostHttps() {
if (Play.id.equals("dev")) {
String[] pieces = request.host.split(":");
String httpsPort = (String) Play.configuration.get("https.port");
return "https://" + pieces[0] + ":" + httpsPort;
} else {
if (request.host.endsWith("domain.com")) {
return "https://secure.domain.com";
} else {
return "https://" + request.host;
}
}
}
/** Renames the host to be https://, handles both Heroku and local testing. */
#Util
public static String redirectHostNotHttps() {
if (Play.id.equals("dev")) {
String[] pieces = request.host.split(":");
String httpPort = (String) Play.configuration.get("http.port");
return "http://" + pieces[0] + ":" + httpPort;
} else {
if (request.host.endsWith("domain.com")) {
return "http://www.domain.com";
} else {
return "http://" + request.host;
}
}
}
}
I modified Secure.login() to call HttpsRequired.redirectToHttps() before it runs, to ensure that all passwords are submitted encrypted. Then, in my Security.onAuthenticated(), I redirect to the homepage on standard HTTP.
This works great on my dev and beta deployments, but in production all of my HTTP requests are redirected to the HTTPS login page. I can still use the whole site in HTTPS, but I want regular HTTP to work too.
All of my pages are protected as members-only and require users to login, using the #With(Secure.class) annotation. I'm thinking that it must be related to the fact that the login happens at secure.domain.com instead of www.domain.com, and that they somehow generate different cookies.
Is there a way to change the login cookie created at secure.domain.com to make it work at www.domain.com?
Check out the documentation for the setting for default cookie domain.
http://www.playframework.org/documentation/1.2.4/configuration#application.defaultCookieDomain
It explains how you can set a cookie to work across all subdomains.
application.defaultCookieDomain
Enables session/cookie sharing between subdomains. For example, to
make cookies valid for all domains ending with ‘.example.com’, e.g.
foo.example.com and bar.example.com:
application.defaultCookieDomain=.example.com