How might I get to the SSL URL defined in the properties of an MVC project? - asp.net-mvc-4

I have SSL enabled and I am trying to write my own RequireHttpsAttribute to allow easy testing with IIS Express. When it redirects, it redirects to port 44301, but I don't want to hard code this, I want to read this from the existing configuration.
public sealed class RequireHttpsAlternativePortAttribute : RequireHttpsAttribute
{
protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
{
base.HandleNonHttpsRequest(filterContext);
//alter the port in the base classes result
var baseRedirect = filterContext.Result as RedirectResult;
if (baseRedirect == null)
{
throw new Exception("No redirect was suppied from the base class");
}
var builder = new UriBuilder(baseRedirect.Url);
var targetPort = 44301; //need this from settings
if (builder.Port == targetPort) return; //already correct port
//change the port
builder.Port = targetPort;
var redirectResult = new RedirectResult(builder.ToString());
filterContext.Result = redirectResult;
}
}
44301 is defined in the MVC project properties under SSL URL. My question is, is this accessible during runtime anywhere?

Related

TCP Client/Server hosted in Kestrel

I would like to create a simple TCP Server / TCP Client and use a Controller to interface with that classes, to then host the controller in a kestrel webserver.
I wanted to use SimpleSockets to create TCP Clients and the Server.
The creator of that library describes two ways of instantiating a TCP-Server either by providing an SSL-Certificate or by just creating a TcpListener without the need of an certificate.
It is described here
I want to use the option by providing an ssl-certificate but I cannot figure out how to provide the constructor with that certficate that is managed by the kestrel webserver, is there any way of injecting it (if that is the right way to do it) into the constructor of the TCP-Server?
If yes how would I inject the certificate?
In the code of the webserver I add the certificate like that:
builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.AllowedCertificateTypes = builder.Configuration.GetSection("Authentication").GetSection("CertificateAuthentication").GetValue<CertificateTypes>("AllowedCertificateTypes");
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices.GetService<CertificateValidationService>();
if (validationService is not null)
{
if (validationService.ValidateCertificate(context.ClientCertificate))
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer),
new Claim(ClaimTypes.Name, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer)
};
context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
context.Success();
return Task.CompletedTask;
}
}
context.Fail("Invalid client certificate");
return Task.CompletedTask;
}
};
})
.AddCertificateCache();
And that is the code of the constructor of my TCP-Server class where I want to inject the certificate into:
public TcpServer(X509Certificate2 certificate)
{
Listener = new SimpleSocketTcpSslListener(certificate);
}
Thanks in advance.

How do I force https redirect on static files in ASP.NET Core 2.1?

I have a ASP.NET Core app that has HTTPS redirection enabled. The problem is that HTTPS redirection doesn´t work on static files, so the front-end is in a different port than the back-end when I enter the site with http and this causes CORS to block all requests made to the back-end. I tried allowing CORS to all requests (for testing, of course) but no matter what I did, the requests failed. Only visiting the front end with https worked.How do I force https redirect on static files with ASP.NET Core?
Based on my expeirence, you must add this code to the startup.cs file
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpsRedirection(options =>
{
options.HttpsPort = 443;
});
You have to love Microsoft documentation. 6 paragraphs below the incomplete example they tell you about this requirement:
If no port is set:
Requests aren't redirected.
You can set port using the following techniques:
The port can be configured by setting the:
ASPNETCORE_HTTPS_PORT environment variable.
http_port host configuration key (for example, via hostsettings.json or a command
line argument).
HttpsRedirectionOptions.HttpsPort. See the preceding
This worked for me.
app.UseStaticFiles(new StaticFileOptions()
{
OnPrepareResponse = (context) =>
{
var request = context.Context.Request;
var response = context.Context.Response;
UrlRewriteUtils.RedirectIfHttp(request, response);
}
});
And here is the Utility method.
public class UrlRewriteUtils
{
public static void RedirectIfHttp(HttpRequest request, HttpResponse response)
{
string reqProtocol;
if (request.Headers.ContainsKey("X-Forwarded-Proto"))
reqProtocol = request.Headers["X-Forwarded-Proto"][0];
else if (request.IsLocal())
reqProtocol = "https";
else
reqProtocol = request.IsHttps ? "https" : "http";
if (reqProtocol.ToLower() != "https")
{
var newUrl = new StringBuilder()
.Append("https://").Append(request.Host)
.Append(request.PathBase).Append(request.Path)
.Append(request.QueryString);
response.Redirect(newUrl.ToString(), true);
}
}
}

DataContractSerializerOperationBehavior is not found when trying to use DataContractResolver

I am trying to use DataContractResolver as an alternative to KnownTypes in WCF.
I have the following code and I've used it before on the server side. But on the client side, the code returns null when trying to find DataContractSerializerOperationBehavior in operation behaviors collection.
public override IMyService CreateProxy(Uri url)
{
ServiceEndpoint endpoint = CreateEndpoint(url);
var channelFactory = new ChannelFactory<IMyService>(endpoint);
InjectResolver(channelFactory.Endpoint);
return channelFactory.CreateChannel();
}
private void InjectResolver(ServiceEndpoint endpoint)
{
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
var behavior = operation.Behaviors.Find<DataContractSerializerOperationBehavior>();
behavior.DataContractResolver = new DerivedTypeResolver(); // behavior is null here!
}
}
Why is the behavior missing?
UPDATE: I found out the real issue is that WCF was using XmlSerializer instead of DataContractSerializer. Is there a way to force a DataContractSerializer instead? Does WCF choose the serializer based on the wsdl? Considering I don't (yet) have the capacity to change the server side, what is my option? XmlSerializer behavior doesn't seem to have a similar option of resolving the type myself.
See here for example on how to create DataContractSerializerOperationBehavior if it does not exist:
private void DataContractBehavior()
{
WSHttpBinding b = new WSHttpBinding(SecurityMode.Message);
Uri baseAddress = new Uri("http://localhost:1066/calculator");
ServiceHost sh = new ServiceHost(typeof(Calculator), baseAddress);
sh.AddServiceEndpoint(typeof(ICalculator), b, "");
// Find the ContractDescription of the operation to find.
ContractDescription cd = sh.Description.Endpoints[0].Contract;
OperationDescription myOperationDescription = cd.Operations.Find("Add");
// Find the serializer behavior.
DataContractSerializerOperationBehavior serializerBehavior =
myOperationDescription.Behaviors.
Find<DataContractSerializerOperationBehavior>();
// If the serializer is not found, create one and add it.
if (serializerBehavior == null)
{
serializerBehavior = new DataContractSerializerOperationBehavior(myOperationDescription);
myOperationDescription.Behaviors.Add(serializerBehavior);
}
// Change the settings of the behavior.
serializerBehavior.MaxItemsInObjectGraph = 10000;
serializerBehavior.IgnoreExtensionDataObject = true;
sh.Open();
Console.WriteLine("Listening");
Console.ReadLine();
}
example from https://msdn.microsoft.com/en-us/library/system.servicemodel.description.datacontractserializeroperationbehavior.aspx

Xamarin Portable Class Library Gets Proxy Access Denied on iPhone Simulator

I've run into a bit of an issue with the iPhone simulator when trying to access a WCF REST service.
I've asked the question on the Xamarin forums, but no joy.
Some context:
I have a PCL for a Xamarin cross platform project, in VS 2012.
I use the Portable Microsoft HttpClient package and the Json.NET package.
I have a pretty simple WCF REST service sitting in the background.
When testing
I can access the service fine from a browser on the dev machine.
I can access it fine using a console application going via the PCL.
I can access it fine via the app, from a real android device on the WiFi network of
the same corporate network.
I can access it fine from Safari on the build Mac.
I can access it fine from Safari on the iPhone simulator on the build Mac.
The issue is, as soon as I try to access the service via the app on the iPhone simulator, I get a 407, Proxy Access Denied error.
Here is the code I'm using to set up the connection:
private static HttpRequestMessage PrepareRequestMessage(HttpMethod method, string baseUri,
string queryParameters, out HttpClient httpClient, string bodyContent)
{
var finalUri = new Uri(baseUri + queryParameters);
var handler = new HttpClientHandler();
httpClient = new HttpClient(handler);
var requestMessage = new HttpRequestMessage(method, finalUri);
if (handler.SupportsTransferEncodingChunked())
{
requestMessage.Headers.TransferEncodingChunked = true;
}
if (method == HttpMethod.Post || method == HttpMethod.Put)
{
requestMessage.Content =
new StringContent(bodyContent, Encoding.UTF8, "application/json");
}
return requestMessage;
}
That code gives me the 407 error.
I have tried setting the proxy by using various combinations of SupportsProxy and SupportsUseProxy. (Both returning false from the simulator.)
I've tried forcing the proxy settings regardless. I've tried setting the credentials on the handler itself. I've tried playing with the UseDefaultCredentials and UseProxy flags. I've also tried setting the IfModifiedSince value in the message header. I've tried using the PortableRest package as well.
All of that only seemed to make things worse. Where I was initially getting the 407 error, the call to httpClient.GetAsync would just immediately return null.
I am at a bit of a loss here, so any help would be greatly appreciated.
PS. For completeness, the rest of the surrounding code that makes the call: (please forgive crappy exception handling, I'm still playing around with the errors)
public static async Task<T> SendRESTMessage<T>(HttpMethod method, string baseUri,
string queryParameters, T contentObject)
{
HttpClient httpClient;
var payload = string.Empty;
if (contentObject != null)
{
payload = JsonConvert.SerializeObject(contentObject);
}
var requestMessage =
PrepareRequestMessage(method, baseUri, queryParameters, out httpClient, payload);
HttpResponseMessage responseMessage = null;
try
{
if (method == HttpMethod.Get)
{
responseMessage = await httpClient.GetAsync(requestMessage.RequestUri);
}
else
{
responseMessage = await httpClient.SendAsync(requestMessage);
}
}
catch (HttpRequestException exc)
{
var innerException = exc.InnerException as WebException;
if (innerException != null)
{
throw new Exception("Unable to connect to remote server.");
}
}
return await HandleResponse<T>(responseMessage);
}
private static async Task<T> HandleResponse<T>(HttpResponseMessage responseMessage)
{
if (responseMessage != null)
{
if (!responseMessage.IsSuccessStatusCode)
{
throw new Exception("Request was unsuccessful");
}
var jsonString = await responseMessage.Content.ReadAsStringAsync();
var responseObject = JsonConvert.DeserializeObject<T>(jsonString);
return responseObject;
}
return default(T);
}
This was my attempt at implementing IWebProxy quick and dirty, which I think could have made things worse:
public class MyProxy : IWebProxy
{
private System.Net.ICredentials creds;
public ICredentials Credentials
{
get
{
return creds;
}
set
{
creds = value;
}
}
public Uri GetProxy(Uri destination)
{
return new Uri("proxy addy here");
}
public bool IsBypassed(Uri host)
{
return true;
}
}
Thanks again for taking the time to read my question.
So I finally got it working.
Turns out it was something really stupid, but being new to iOS mobile dev and the fact that the service worked via Safari on the simulator threw me for a loop.
I read that the simulator uses the proxy settings as defined on the Mac. So I went to the network settings and added the service address to the proxy bypass list.
Works like a charm now.
If anybody feels there is a better way to do this, please add your opinions.

Dealing with Azure staging crazy URL

i'm deploying a webrole in azure that contains a web-site and a wcf service...
The site consumes services from the wcf.
The problem here is that the staging deploy creates a crazy url for the endpoints and i have to keep changing the endpoints in the web.config...
I'm wondering if theres a way to either "predict" what the url will be or to force one or even point to a generic host such as "localhost"???
You should be able to use role discovery to find the WCF endpoint. See this SO answer here and the blog post it links to.
My own abstract base class for connecting to azure services was based on that article. It uses role discovery to crate a channel like this:
#region Channel
protected String roleName;
protected String serviceName;
protected String endpointName;
protected String protocol = #"http";
protected EndpointAddress _endpointAddress;
protected BasicHttpBinding httpBinding;
protected NetTcpBinding tcpBinding;
protected IChannelFactory channelFactory;
protected T client;
protected virtual AddressHeader[] addressHeaders
{
get
{
return null;
}
}
protected virtual EndpointAddress endpointAddress
{
get
{
if (_endpointAddress == null)
{
var endpoints = RoleEnvironment.Roles[roleName].Instances.Select(i => i.InstanceEndpoints[endpointName]).ToArray();
var endpointIP = endpoints.FirstOrDefault().IPEndpoint;
if(addressHeaders != null)
{
_endpointAddress = new EndpointAddress(new Uri(String.Format("{1}://{0}/{2}", endpointIP, protocol, serviceName)), addressHeaders);
}
else
{
_endpointAddress = new EndpointAddress(String.Format("{1}://{0}/{2}", endpointIP, protocol, serviceName));
}
}
return _endpointAddress;
}
}
protected virtual Binding binding
{
get
{
switch (protocol)
{
case "tcp.ip":
if (tcpBinding == null) tcpBinding = new NetTcpBinding();
return tcpBinding;
default:
//http
if (httpBinding == null) httpBinding = new BasicHttpBinding();
return httpBinding;
}
}
}
public virtual T Client
{
get
{
if (this.client == null)
{
this.channelFactory = new ChannelFactory<T>(binding, endpointAddress);
this.client = ((ChannelFactory<T>)channelFactory).CreateChannel();
((IContextChannel)client).OperationTimeout = TimeSpan.FromMinutes(2);
var scope = new OperationContextScope(((IContextChannel)client));
addCustomMessageHeaders(scope);
}
return this.client;
}
}
#endregion
And in a derived class I pass it the following variables (for example):
this.roleName = "WebServiceRole";
this.endpointName = "HttpInternal";
this.serviceName = "services/Accounts.svc";
I never need to refer to the staging (or production) URLs at all.
See my answer here for more details: Add WCF reference within the same solution without adding a service reference
There is no way to either predict the GUID, control it, or use some constant name.
What you can do, to make things easier, is to move the URL into .CSCFG and update the URL of the WCF service from Azure Management Portal