Serilog ElasticSearch sink not working in WebApi - asp.net-web-api

I'm using Serilog in an Azure Worker Role & a WebApi with the ElasticSearch sink.
Everything works fine on the Worker Role.
On the WebApi I tried the Trace & Email sinks and they work fine. ElasticSearch sink is not logging at all.
Here is my configuration:
var logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Trace()
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("https://myElasticServer")))
.CreateLogger();
If I try to write Logs in a controller, I have them in the Trace but nothing in Trace.

The problem came from a self signed certificate.
I've created my own CertificateValidation method to ignore certificate validation based on an exclusion list
private bool MyCertificateValidationCallback(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
var request = sender as HttpWebRequest;
if (request != null)
{
var exclusion = ConfigurationManager.AppSettings["CertificateExclusion"];
if (exclusion.Contains(request.Host))
return true;
}
return false;
}
And register it when the application starts
ServicePointManager.ServerCertificateValidationCallback = MyCertificateValidationCallback;

Related

Upgrade code from org.eclipse.jetty.websocket.websocket-client to org.eclipse.jetty.websocket.websocket-jakarta-client

I have the following application code in an application that I would like to migrate to Spring3 in order to do so javax is replaced with jakarta.
Any one have any Idea how to migrate the following code:
// Let's create and start the Web Socket
//
// For internal test, we have a self-signed certificate. So we need to short cut certificate check.
// DO NOT DO THAT IN PRODUCTION!
boolean trustAll = (System.getProperty("com.graphql-java-generator.websocket.nosslcheck") != null);
org.eclipse.jetty.util.ssl.SslContextFactory.Client sslContextFactory = new org.eclipse.jetty.util.ssl.SslContextFactory.Client(
trustAll);
org.eclipse.jetty.client.HttpClient httpClient = new HttpClient(sslContextFactory);
org.eclipse.jetty.websocket.client.WebSocketClient wsClient = new WebSocketClient(httpClient);
SubscriptionClientWebSocket<R, T> subscriptionClientWebSocket = new SubscriptionClientWebSocket<R, T>(request,
subscriptionName, subscriptionCallback, subscriptionType, messageType,
graphQLRequest.getGraphQLObjectMapper());
URI uri = getWebSocketURI();
try {
wsClient.start();
org.eclipse.jetty.websocket.client.ClientUpgradeRequest clientUpgradeRequest = new ClientUpgradeRequest();
wsClient.connect(subscriptionClientWebSocket, uri, clientUpgradeRequest);
logger.debug("Connecting to {}", uri);
} catch (Exception e) {
String msg = "Error while opening the Web Socket connection to " + uri;
logger.error(msg);
throw new GraphQLRequestExecutionException(msg, e);
}
Having not found any documentation on how to proceed with this migration.
Tried using the JakartaWebSocketClientContainer but could not find how to use with an UpgradeRequest
Your code is not using javax.websocket, so there's nothing to upgrade.
The techniques you are using in your code to manage the SSL behavior is also not possible in either javax.websocket or jakarta.websocket (There is no API you can use to manage SSL/TLS in those)

connect to a server with a self-signed certificate

Ive been doing some research about how to consume a web api executed on my localhost throught a xamarin app. The web api works perfect, I can adding and getting the data to/from my sql server using a web browser but if I try to connect xamarin to it Ive always received authentication error (Mono.Btls.MonoBtlsException: Ssl error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED). Im basically doind this. I followed this post:
http://xamarininterviewquestion.blogspot.com/2019/06/ssl-certificate-and-public-key-pinning.html
So as it definitly didnt work, Id like to try another way;
Set TLSConfig DangerousAcceptAnyServerCertificateValidator to true. Because for know Im happy if Im able to test it.
Thats cool but as Im not a pro I have no idea about implement this;
var httpHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
Ive got "DangerousAcceptAnyServerCertificateValidator" doesnt have a definition.
Thank you all in advance and sorry if Ive not been clear.
DangerousAcceptAnyServerCertificateValidator isn't applicable to Xamarin platforms, according to its documentation.
But literally you can write the same code like,
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
HttpClient client = new HttpClient(handler);
https://stackoverflow.com/a/64741829/11182
if you are using Refit then you can do this
public HttpClient PreparedClient()
{
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => { return true; };
HttpClient client = new HttpClient(handler) { BaseAddress = new Uri(EndpointConstants.BaseUrl) };
return client;
}
private T RefitApi<T>() => RestService.For<T>(PreparedClient());
and if you need to specify settings you can do this
private T RefitApiWithToken<T>() => RestService.For<T>(PreparedClient(), refitSettings);
When using Refit for Xamarin forms
public HttpClient PreparedClient()
{
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => { return true; };
HttpClient client = new HttpClient(handler) { BaseAddress = new Uri(EndpointConstants.BaseUrl) };
return client;
}
var apiResponse = RestService.For<T>(PreparedClient());

How to implement Exchange online OAuth2.0 for unmanaged EWS API?

For managed EWS code, I have used to OAuth 2.0 to get token and it worked.
For unmanaged EWS, it is failing to connect to Exchange as an unauthorized error.
Below is the code to access unmanaged EWS.
How to make below code work with OAuth token instead of passing credentials as below?.
Binding = new ExchangeServiceBinding
{
Url = ServerUrl,
Credentials = new OAuthCredentials(token),
RequestServerVersionValue = new RequestServerVersion { Version = ExchangeVersionType.Exchange2007_SP1 },
ExchangeImpersonation = null
};
Above is not working as credential is asking of type ICredentials and it is not accepting token. Please help me.
Below is the code how I direct access managed EWS.
var authResult = await pca.AcquireTokenByUsernamePassword(ewsScopes, credential.UserName, credential.SecurePassword).ExecuteAsync();
configure the ExchangeService with the access token
ExchangeService = new ExchangeService();
ExchangeService.Url = new Uri(ServerUrl);
ExchangeService.Credentials = new OAuthCredentials(authResult.AccessToken);
One method i use (as I've never worked out how to override the WSDL classes) is if you modify the Reference.cs file that gets generated in the web references directory you can modify the GetWebResponse command (In this case the token is being passed via the credentials object password property but there a number of different approaches you can take here) eg
private String AnchorMailbox;
private bool oAuth;
protected override System.Net.WebResponse GetWebResponse(System.Net.WebRequest req)
{
if (xAnchorMailbox != null)
{
if (xAnchorMailbox != "")
{
req.Headers.Add("X-AnchorMailbox", AnchorMailbox);
}
}
if(req.Credentials is System.Net.NetworkCredential)
{
if(oAuth){
req.Headers.Add("Authorization", ("Bearer " + ((System.Net.NetworkCredential)req.Credentials).Password));
}
}
System.Net.HttpWebResponse
rep = (System.Net.HttpWebResponse)base.GetWebResponse(req);
return rep;
}

Aspnet core web api protected with Azure

I have a web api in my organization built with aspnet core. We want to publish that api to be consumed by an android app, a mvc5 app and an aspnet core mvc6 app. How can I configure the web api in azure so that the apps that consume it don't ask to login. The web apps, are already protected with azure, but when I protect the web api with azure I get a 401 when I make a request to it. I don't know how to configure the app in azure or the code I must configure in the api. I've read a lot but I don't find a way to acomplish this. All I want is to login in my web app, and the web app starts to ask data to the web api through ajax. I should send in the ajax request some sort of bareer token, but i don`t know what config i must do in azure and in the apps. I hope you can help me.
After you protected the web API with Azure AD, we need to send to access token with request for the web API for authorization. And we can get the access token when the users call the web API from web app. Here is the code to acquire the token in the web app for your reference:
public async Task<IActionResult> Index()
{
AuthenticationResult result = null;
List<TodoItem> itemList = new List<TodoItem>();
try
{
string userObjectID = (User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID, HttpContext.Session));
ClientCredential credential = new ClientCredential(Startup.ClientId, Startup.ClientSecret);
result = await authContext.AcquireTokenSilentAsync(Startup.TodoListResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
//
// Retrieve the user's To Do List.
//
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, TodoListBaseAddress + "/api/todolist");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await client.SendAsync(request);
//
// Return the To Do List in the view.
//
if (response.IsSuccessStatusCode)
{
List<Dictionary<String, String>> responseElements = new List<Dictionary<String, String>>();
JsonSerializerSettings settings = new JsonSerializerSettings();
String responseString = await response.Content.ReadAsStringAsync();
responseElements = JsonConvert.DeserializeObject<List<Dictionary<String, String>>>(responseString, settings);
foreach (Dictionary<String, String> responseElement in responseElements)
{
TodoItem newItem = new TodoItem();
newItem.Title = responseElement["title"];
newItem.Owner = responseElement["owner"];
itemList.Add(newItem);
}
return View(itemList);
}
else
{
//
// If the call failed with access denied, then drop the current access token from the cache,
// and show the user an error indicating they might need to sign-in again.
//
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
var todoTokens = authContext.TokenCache.ReadItems().Where(a => a.Resource == Startup.TodoListResourceId);
foreach (TokenCacheItem tci in todoTokens)
authContext.TokenCache.DeleteItem(tci);
ViewBag.ErrorMessage = "UnexpectedError";
TodoItem newItem = new TodoItem();
newItem.Title = "(No items in list)";
itemList.Add(newItem);
return View(itemList);
}
}
}
catch (Exception ee)
{
if (HttpContext.Request.Query["reauth"] == "True")
{
//
// Send an OpenID Connect sign-in request to get a new set of tokens.
// If the user still has a valid session with Azure AD, they will not be prompted for their credentials.
// The OpenID Connect middleware will return to this controller after the sign-in response has been handled.
//
return new ChallengeResult(OpenIdConnectDefaults.AuthenticationScheme);
}
//
// The user needs to re-authorize. Show them a message to that effect.
//
TodoItem newItem = new TodoItem();
newItem.Title = "(Sign-in required to view to do list.)";
itemList.Add(newItem);
ViewBag.ErrorMessage = "AuthorizationRequired";
return View(itemList);
}
//
// If the call failed for any other reason, show the user an error.
//
return View("Error");
}
And below is the code sample which use JwtBearerAppBuilderExtensions to add OpenIdConnect Bearer authentication capabilities to an HTTP application pipeline for the web API to verify the token:
public class Startup
{
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Add the console logger.
loggerFactory.AddConsole(LogLevel.Debug);
// Configure the app to use Jwt Bearer Authentication
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAD:Tenant"]),
Audience = Configuration["AzureAd:Audience"],
});
}
}
The full code sample you can refer here.
Note: to run this sample successfully, we need to modify the Title and Owner to lowercase title, owner in the ToDoController of web app:
foreach (Dictionary<String, String> responseElement in responseElements)
{
TodoItem newItem = new TodoItem();
newItem.Title = responseElement["title"];
newItem.Owner = responseElement["owner"];
itemList.Add(newItem);
}
You can use Azure OpenIdConnect for federated authentication. A good article from microsoft below -
Calling a web API in a web app using Azure AD and OpenID Connect

WebRequest returns 404 when switching to SSL

Having built an app using PCL method in Xamarin and have had it working 100% using standard HTTP I now changed the remote test server to use SSL with self signed certs.
The app contacts a custom API for logging onto a server and querying for specific data.
I've changed the app to look at SSL now and initially got an error regarding Authentication not working or something but turned off SSL related errors for testing using:
ServicePointManager.ServerCertificateValidationCallback += (o, certificate, chain, errors) => true;
in my AppDelegate files FinishedLaunching method which got over that error.
I'm now getting a 404 / protocol error when trying to do my Login POST to the given URL.
I am using HttpWebRequest for my RESTful calls and this works fine if I change back to plain http.
Not sure why but some articles suggested using ModernHttpClient, which I did. I imported the component (also added the package using NuGet) to no avail.
Am I missing something else that I should be configuring in my code related to httpwebresponse when contacting the SSL server or is this component simply incapable of speaking to an SSL server?
My login function is as follows (Unrelated code removed/obfuscated):
public JsonUser postLogin(string csrfToken, string partnerId, string username, string password){
string userEndPoint = SingletonAppSettngs.Instance ().apiEndPoint;
userEndPoint = userEndPoint.Replace ("druid/", "");
var request = WebRequest.CreateHttp(string.Format(this.apiBaseUrl + userEndPoint + #"user/login.json"));
// Request header collection set up
request.ContentType = "application/json";
request.Headers.Add ("X-CSRF-Token", csrfToken);
// Add other configs
request.Method = "POST";
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string json_body_content = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}";
streamWriter.Write(json_body_content);
streamWriter.Flush();
streamWriter.Close();
}
try{
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader (httpResponse.GetResponseStream ())) {
var content = reader.ReadToEnd ();
content = content.Replace ("[],", "null,");
content = content.Replace ("[]", "null");
if (content == null) {
throw new Exception ("request_post_login - content is NULL");
} else {
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.NullValueHandling = NullValueHandling.Ignore;
JsonUser deserializedUser = JsonConvert.DeserializeObject<JsonUser>(content, jss);
if(content.Contains ("Hire company admin user")){
deserializedUser.user.roles.__invalid_name__5 = "Hire company admin user";
deserializedUser.user.roles.__invalid_name__2 = "authenticated user";
}
return deserializedUser;
}
}
}catch(Exception httpEx){
Console.WriteLine ("httpEx Exception: " + httpEx.Message);
Console.WriteLine ("httpEx Inner Exception: " + httpEx.InnerException.Message);
JsonUser JsonUserError = new JsonUser ();
JsonUserError.ErrorMessage = "Error occured: " + httpEx.Message;
return JsonUserError;
}
}
When making a Web Request using ModernHttpClient, I generally follow the pattern below. Another great library created by Paul Betts is refit, and can be used to simplify rest calls.
using (var client = new HttpClient(new NativeMessageHandler(false, false)))
{
client.BaseAddress = new Uri(BaseUrl, UriKind.Absolute);
var result = await Refit.RestService.For<IRestApi>(client).GetData();
}
The second parameter for NativeMessageHandler should be set to true if using a customSSLVerification.
Here's a look at IRestApi
public interface IRestApi
{
[Get("/foo/bar")]
Task<Result> GetMovies();
}
Number of things I had to do to get this to work.
The Self Signed Cert had to allow TLS 1.2
As the API is Drupal based, HTTPS had to be enabled on the server and a module installed to manage the HTTP specific pages.

Resources