Where to place configuration settings for Web API - entity-framework

I am using Web API and entity framework. Initially my connection string is in web.config file. Web API is hosted in IIS Server. Connection string will be encrypted by utility(executable not known may be third party) so when connection string will encrypt in web.config then API will restart again and we don't want to restart the API.
Can I keep all my settings in app.config instead of web.config to avoid restart of web API or registry is a good choice to keep connection string over config files?
I have used below code read connection string from app.config.
string codeBase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
string configPath = Path.Combine(Path.GetDirectoryName(path), "database.config");
if (File.Exists(configPath))
{
var configMap = new ExeConfigurationFileMap
{
ExeConfigFilename = configPath
};
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
string connectionString = config.ConnectionStrings.ConnectionStrings["DatabaseContext"].ToString();
}
Please suggest.

Related

403 Forbidden error while accessing Azure web api using certificate authentication

I am getting 403 Forbidden exception while accessing simple azure webapi with certificate authentication, only while accessing from asp.net web application. I am using WebClient inherited object to overide GetWebRequest to add client certificate.
public class CertificateWebClient : WebClient
{
private readonly X509Certificate2 certificate;
public CertificateWebClient(X509Certificate2 cert)
{
certificate = cert;
}
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.ClientCertificates.Add(certificate);
return request;
}
}
And I am using the object CertificateWebClient DownloadString function to access the web api.
X509Certificate2 newCertificate = new X509Certificate2("bytearray");
CertificateWebClient webClient = new CertificateWebClient(newCertificate)
{
Proxy = new WebProxy("proxy address")
};
var result = webClient.DownloadString("https://webapiaddress/api/Values");
I am accessing the web api in the similar manner in windows forms and it works absolutely fine.
I could resolve this issue by storing and retrieving the certificate from Azure key vault in Base 64 string format. Using Convert.ToBase64String("raw certificate data") and Convert.FromBase64String("base64 cert string"), so I had to modify the above code as
X509Certificate2 newCertificate = new X509Certificate2(Convert.FromBase64String("base64 cert string"));
Only base 64 format keeps the certificate raw data intact while Adding/Retrieving certificate data to azure key vault.
The Certificate should have been ideally added to Azure key vault certificate store but the project requirement was to store it as key.

SSL certificate related issue while calling rest servcies

From client (eg: https://localhost:8080/) we are passing the certificate related values and calling the rest services ( hosted on different port - https://localhost:446/serviceName).
The issue is like, when we try to pass the certificate , SSL handshake is happening correctly (no error on debug) , but the certificate value is not passed to the service hosted on another port. Certificate value is accessed in server code by referring to (X509Certificate)httpReq.getAttribute("javax.servlet.request.X509Certificate");
Note : We use Spring boot application which intenally runs on tomcat server.And desired CA authorised certificates, keystore and truststore are present in resource path in both the projects (client and service hosted). In rest service project config file, the client-auth is set to false.
Sample code snippet used to call rest service:
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(restserviceTruststore)
.loadKeyMaterial(restserviceKeyStore, password).build();
HttpClient client = HttpClients.custom() .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
.setSslcontext(sslContext).build();
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(client));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity<String> request = new HttpEntity<>(XML, headers);
response = restTemplate.postForObject(endpointURL, request, String.class);
Question:
1) From client what keystore and trustore should we need to pass to SSLContext? Is it server's keystore /truststore or clients?
2)What are the exact steps to be followed to resolve this issue.

ASP double hop request in kerberos delegation scenario

Please help!
I need my asp application to request remote systems with credentials of impersonated user. But always get 401 Unauthorized errors.
I made all configurations from here: https://support.microsoft.com/en-us/help/810572/how-to-configure-an-asp-net-application-for-a-delegation-scenario
Kerberos is configured and working in my app and my test remote app(i see kerberos tickets in fiddler). Delegation, spns and everything is configured.
Thats my code usnig System.Net.Http.httpclient:
HttpClientHandler handler = new HttpClientHandler()
{
UseDefaultCredentials = true,
PreAuthenticate = true
};
using (HttpClient client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Accept.Clear();
var method = new HttpMethod("GET");
var request = new HttpRequestMessage(method, "http://testdelegationapp.avp.ru/");
var response = client.SendAsync(request).Result;
}
In fact http request is made by Apppool account (I get 401 error when restricting access to Apppool account in remote app IIS)
Here: How to get HttpClient to pass credentials along with the request?
is claimed that HttpClient cant pass security token to another thread, and its better to use synchronous methods of System.Net.WebClient
Code using webclient:
var wi = (WindowsIdentity)HttpContext.User.Identity;
var wic = wi.Impersonate();
try
{
string URI = "http://testdelegationapp.avp.ru/";
using (WebClient wc = new WebClient())
{
wc.UseDefaultCredentials = true;
string response = wc.DownloadString(URI);
}
}
finally
{
wic.Undo();
}
Result is even worse, the same 401 error, but in fiddler i can see that webclient using NTLM ticket to get to remote app!
Configuring of flowing tokens throw threads from here :Unable to authenticate to ASP.NET Web Api service with HttpClient
doesnt help either. SecurityContext.IsWindowsIdentityFlowSuppressed() is false.
WindowsIdentity.GetCurrent().Name and Thread.CurrentPrincipal.Identity.Name shows impersonated user as it should be.
All that time problem was in chrome browser, by default it prohobits kerberos delegation. You shoud add the following to registry:
Path: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome ;
string: AuthNegotiateDelegateWhitelist ;
value: *.avp.ru
So, now my working configuration is
HttpClient for web requests.
ASP impersonation ON in IIS if you want to execute all your app under
delegated credentials. If you want method specific delegation, then use:
var wi = (WindowsIdentity)HttpContext.User.Identity;
var wic = wi.Impersonate();
wic.Undo();
HttpClient executes request in another thread , so in aspnet_config.config we need following changes:
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
You can find aspnet_config.config in:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet.config
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet.config
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\aspnet.config
C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet.config

WCF REST Service - Self Host Windows Service - How to use % in URL

I have a REST WCF service that has a method that gets a parameter as a string
When I use the %23 in the Url I got an error message: Endpoint not found!
e.g:
-- Id #9999
http://localhost:8000/MyService/GetData/Id/%239999 (%23 means # symbol encoded)
If I use without % symbol it works fine
http://localhost:8000/MyService/GetData/Id/10
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, UriTemplate = "GetData/id/{id}")]
string GetData(string value);
}
I Host the Service on Windows Service:
ServiceHost host = new ServiceHost(typeof(Service1), "http://localhost:8000");
WebHttpBinding binding = new WebHttpBinding();
ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IService1), binding, "MyService");
WebHttpBehavior httpBehavior = new WebHttpBehavior();
endpoint.Behaviors.Add(httpBehavior);
host.Open();
I've found this post:
http://www.hanselman.com/blog/ExperimentsInWackinessAllowingPercentsAnglebracketsAndOtherNaughtyThingsInTheASPNETIISRequestURL.aspx but it doesn't work since I'm not hosting WCF on IIS I'm hosting it on Windows Service instead
I found the solution thanks to this thread:
How can I pass slash and other 'url sensitive' characters to a WCF REST service?
Solution:
<configuration>
<system.net>
<settings>
<httpListener unescapeRequestUrl="false"/>
</settings>
</system.net>
</configuration>
its not a best pratice to use some special chars in urls. please so consider not using them.
take a look at MSDN - UriTemplate

How do I code Citrix web sites to use a Secure Gateway (CSG)?

I'm using Citrix's sample code as a base and trying to get it to generate ICA files that direct the client to use their Secure Gateway (CSG) provider. My configuration is that the ICA file's server address is replaced with a CSG ticket and traffic is forced to go to the CSG.
The challenge is that both the Citrix App Server (that's providing the ICA session on 1494) and the CSG have to coordinate through a Secure Ticket Authority (STA). That means that my code needs to talk to the STA as it creates the ICA file because STA holds a ticket that the CSG needs embedded into the ICA file. Confusing? Sure! But it's much more secure.
The pre-CSG code looks like this:
AppLaunchInfo launchInfo = (AppLaunchInfo)userContext.launchApp(appID, new AppLaunchParams(ClientType.ICA_30));
ICAFile icaFile = userContext.convertToICAFile(launchInfo, null, null);
I tried to the SSLEnabled information to the ICA generation, but it was not enough. here's that code:
launchInfo.setSSLEnabled(true);
launchInfo.setSSLAddress(new ServiceAddress("CSG URL", 443));
Now, it looks like I need to register the STA when I configure my farm:
ConnectionRoutingPolicy policy = config.getDMZRoutingPolicy();
policy.getRules().clear();
//Set the Secure Ticketing Authorities (STAs).
STAGroup STAgr = new STAGroup();
STAgr.addSTAURL(#"http://CitrixAppServerURL/scripts/ctxsta.dll");
//creat Secure Gateway conenction
SGConnectionRoute SGRoute = new SGConnectionRoute(#"https://CSGURL");
SGRoute.setUseSessionReliability(false);
SGRoute.setGatewayPort(80);
SGRoute.setTicketAuthorities(STAgr);
// add the SGRoute to the policy
policy.setDefault(SGRoute);
This is based on code I found on the Citrix Forums; however, it breaks my ability to connect with the Farm and get my application list!
Can someone point me to an example of code that works? Or a reference document?
The code in the question is basically right, but I was trying too hard to inject configuration into the launching ICA generator.
Note: Using the WebInterface.conf file for guidance is a good way to determine the right config settings. Even if the code is right, the configuration is very touchy!
Most of the Citrix Secure Gateway (CSG) / Secure Ticket Authority (STA) magic happens when the policy for the initial connection to the farm is established. Specifically, in Global.asax.cs, you must have the following blocks of code:
1) you must have a valid STAGroup:
//Set the Secure Ticketing Authorities (STAs).
STAGroup STAgr = new STAGroup();
STAgr.addSTAURL(#"http://[STA URL]/scripts/ctxsta.dll");
2) the you must create a CSG connection (with the STA mapped):
//create Secure Gateway conenction
SGConnectionRoute SGRoute = new SGConnectionRoute(#"[CSG FQDN without HTTPS]");
SGRoute.setUseSessionReliability(false);
SGRoute.setGatewayPort(443);
SGRoute.setTicketAuthorities(STAgr);
3) you need to set the policy default
// Create a DMZ routing policy
ConnectionRoutingPolicy policy = config.getDMZRoutingPolicy();
policy.getRules().clear();
policy.setDefault(SGRoute);
4) you need to tell the launchInfo that you want to be CGP enabled:
launchInfo.setCGPEnabled(true);
WARNING: The SSL enabled as a red herring.
There's another way to do this that is cleaner and more configurable. The code can be setup to use the webinterface.conf file that the default Citrix Web Interface uses.
The following code should replace all of the farmConfig, STAGroup, ConnectionRoutinePolcy, mess in the above sample.
InputStream inputStream = new FileInputStream(#"C:\temp\WebInterface.conf");
CtxConfig configInput = new CtxConfig(inputStream);
Map settingsMap = configInput.getSettingsMap();
WIConfiguration wiConfiguration = ConfigurationParser.buildWIConfiguration(settingsMap);
com.citrix.wing.config.Configuration config = new com.citrix.wing.config.Configuration();
config.setGlobalConfig(wiConfiguration.getGlobalConfig());
config.setMPSFarmConfigs(wiConfiguration.getMPSFarmConfigs());
config.setDMZRoutingPolicy(wiConfiguration.getDMZRoutingPolicy());
config.setClientProxyPolicy(wiConfiguration.getClientProxyPolicy());
// Create a StaticEnvironmentAdaptor instance.
WIASPNetStaticAdaptor staticEnvAdaptor = new WIASPNetStaticAdaptor(this);
// Create a WebPNBuilder instance.
WebPNBuilder builder = WebPNBuilder.getInstance();
Application["WebPNBuilder"] = builder;
// Create a WebPN instance from the configuration.
WebPN webPN = builder.createWebPN(config, staticEnvAdaptor);
Application["WebPN"] = webPN;
Another note on this problem from using the JICA client with an internal certificate (non-trusted root).
The JICA client does not let you accept a certificate from a non-trusted root, so it was required to add the certificate to the Java CA store. Adding it to the Windows store does not do any good!
Get your dev root CA, then navigate to bin directory of the latest Java install (typically, under c:\program files\java\jre*** )
Execute the following command:
keytool -import -trustcacerts -keystore "..\lib\security\cacerts" -file "c:\temp\root.cer" -alias myroot
I'll let you Google for the password because your supposed to changeit [sic].