Correlation Failed, Remote Login. AspNet Core Identity Server - identityserver4

Trying to gain some basic understanding of how this process works as I am receiveing the Correlation failed error. Let me first begin my describing the issue I'm encountering...
QAT is not working properly and is configured as follows:
I have an Identity Server running behind a load balancer for QAT.
All requests sent to the load balancer are https.
The traffic being forwarded to each application server (2 seperate servers in this case) is http.
The Netscaler is adding all necessary X-Forwarded items to the header.
I have another application that also sits behind the load balancer for QAT.
There are 2 seperate servers hosting this application which the netscaler will forward the traffic to.
This application is configured to use the X-Forwarded info from the netscaler.
It is designed to authenticate using the above-mentioned Identity Server.
My issue is that I end up with a never ending loop between the second application and the Identity Server when I deploy to QAT. This is strange to me as my SYS environment works perfectly. My sys environment has a seperate instance of Identity Server and the second Application mentioned (except that there is only a single instance of each application being forwarded to). This also goes through the netscaler and does all the X-Forwarded magic mentioned earlier.
In both situations the setup is identical. The only difference is that QAT has multiple servers hosting each app and SYS only has 1 server hosting each app.
My question is why would this behave differently?
Why would this work in sys but not in qa?
I think at this point we can rule out the callback path, cookie settings, etc... b/c it work in SYS.
Could it be that I need to implement some sore of Data Protection Key middleware in both the identity server and the other applciation? On that note, I really dont understand the Data Protection Keys. Would both the identity server and the seperate application need to store their Keys in the same location (whether that be in the database or filesystem) in order to be able to decrypt the information stored in the cookie...
Any help is greatly appreciated.

It was definitely the Data Protection Keys that were the issue. My solution was simple. Save the encryption key as part of the deployment process, Create an IXmlRepository, and then add that to the startup. Easy Peasy.
using Microsoft.AspNetCore.DataProtection.Repositories;
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
namespace Myapp.Encryption.Repositories
{
public class EncryptionRepository : IXmlRepository
{
private String Key { get; set; }
public EncryptionRepository()
{
var year = Convert.ToString(DateTime.Now.Year + 2);
var key = "<key id=\"983440f7-626b-46e4-8bfa-7c3d6d9d4619\" version=\"1\">" +
" <creationDate>2019-11-13T17:42:58.889085Z</creationDate>" +
" <activationDate>2019-11-13T17:42:58.3843715Z</activationDate>" +
" <expirationDate>" + year + "-02-11T17:42:58.3843715Z</expirationDate>" +
" <descriptor deserializerType=\"Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60\">" +
" <descriptor>" +
" <encryption algorithm=\"AES_256_CBC\" />" +
" <validation algorithm=\"HMACSHA256\" />" +
" <masterKey p4:requiresEncryption=\"true\" xmlns:p4=\"http://schemas.asp.net/2015/03/dataProtection\">" +
" <value>{{Your Encryption Key }}</value>" +
" </masterKey>" +
" </descriptor>" +
" </descriptor>" +
"</key>";
Key = key;
}
public IReadOnlyCollection<XElement> GetAllElements()
{
var collection = new List<XElement>();
collection.Add(XElement.Parse(Key));
return collection;
}
public void StoreElement(XElement element, String friendlyName)
{
// Not required as key is hard coded
}
}
}
services.AddSingleton<IXmlRepository, EncryptionRepository>();
services.AddDataProtection().AddKeyManagementOptions(a => a.XmlRepository = (services.BuildServiceProvider()).GetService<IXmlRepository>());

Related

Need to supply DB password to run evolutions at run time - Play + Slick

I need to avoid storing plain text passwords in config files, and so I'm storing the Postgres password externally (in AWS Secrets Manager).
Similarly to the solution provided here:
Encrypted database password in Play + Slick + HikariCP application, I've been able to override dbConfig and supply the password to my DAO classes like this:
trait MyDaoSlick extends MyTableDefinitions with HasDatabaseConfig[MyPostgresDriver] {
protected val dbConfigProvider: DatabaseConfigProvider
override protected val dbConfig: DatabaseConfig[MyPostgresDriver] = secretDbConfig(dbConfigProvider)
def secretDbConfig(dbConfigProvider: DatabaseConfigProvider): DatabaseConfig[MyPostgresDriver] = {
DatabaseConfig.forConfig[MyPostgresDriver]("", dbConfigProvider.get[MyPostgresDriver].config
.withValue("db.user", ConfigValueFactory.fromAnyRef(getUN))
.withValue("db.password", ConfigValueFactory.fromAnyRef(getPWD)))
}
}
This works great for regular DB queries, however evolutions bypass this and still expect the username and the password to be in application.conf, which kind of defeats the purpose of the password being a secret.
Any advice on how evolutions could get the DB credentials from a function?
I ran into the same issue, and I managed to resolve it like this:
Create a custom application loader, as shown here: https://www.playframework.com/documentation/2.7.x/ScalaDependencyInjection#Advanced:-Extending-the-GuiceApplicationLoader
Inside the custom loader's builder, append the DB configuration parameters for Slick:
val extra = Seq(
"slick.dbs.default.db.url" -> secrets.url,
"slick.dbs.default.db.user" -> secrets.user,
"slick.dbs.default.db.password" -> secrets.pass
)
Nothing else needs to be changed, as you've basically added the configuration needed for anything Slick, evolutions included.
On older versions of Play, we used to do this inside GlobalSettings.onLoadConfig, but, at some point, that has been deprecated in favour of DI. More details here: https://www.playframework.com/documentation/2.7.x/GlobalSettings

Specflow-Share browser session between features if triggered between steps

I have implemented Specflow to reuse some steps across features as in this example -Specflow,Selenium-Share data between different Step definitions or classes .Since, in our project, we are integrating multiple features & reusing them. What is the best way to share browser session across features if its triggered in between steps as per the above approach?
My Scenario:
Once an application created, I need to launch new session, login different User-set different services and approve it.
But after logging in fails with below error on Step definition 4 in reused Whenstep of Given(Set the service to (.*)). That particular step is from different feature, hence the new session needs to be used in those steps. The LaunchURl method below is just launching the website with url, no new session created - This works fine
OpenQA.Selenium.WebDriverException : Unexpected error. System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it "IP here"
[Given(#"A New Application is added")]
public void GivenANewApplicationIsAdded()
{
Given("UK_The Service is set");
Given("User Navigated to New Application screen");
When("User fills up form as in data row 1");
Then("new SID generated");
}
[Given(#"New Browser Launched")]
public void GivenNewBrowserLaunched()
{
SeleniumContext sl = new SeleniumContext();
this.seleniumContext = sl;
}
[Given(#"Login is successful with ""(.*)"" and ""(.*)""")]
public void GivenLoginIsSuccessfulWithAnd(string userName, string password)
{
SuperTests spr = new SuperTests();
_driver = spr.LaunchURL(seleniumContext.WebDriver);
//seleniumContext.WebDriver = _driver;
LoginPage lg = new LoginPage(_driver);
lg.LoginProcess(userName, password);
}
[Given(#"Set the service to ""(.*)""")]
public void GivenSetTheServiceTo(string serviceId)
{
When("Select a Service from the option "+serviceId);
Then("The Services is changed to the one selected " + serviceId);
}
In other feature
[When(#"Select a Service from the option (.*)")]
public void WhenSelectAServiceFromTheOptionTestTeam(string p0)
{
HomePage mst = new HomePage(seleniumContext.WebDriver);
mst.SetServiceId(p0);
}
The 2 work around what we figured was
Create a new instance of binding class to call the methods or steps as shown below
[Given(#"Set the service to ""(.*)""")]
public void GivenSetTheServiceTo(string serviceId)
{
var serIdSteps = new UK_SetServiceIDSteps(seleniumContext);
serIdSteps.WhenUK_SelectAServiceFromTheOptionTest(serviceId);
serIdSteps.ThenUK_TheServicesIsChangedToTheOneSelected(serviceId);
}
or
tried this which worked as well- basically calling a new method to create a new session. for this I need not create any new instance for Binding class. Called the Step directly.
[Given(#"New Browser Launched")]
public void GivenNewBrowserLaunched()
{
SuperTests spr = new SuperTests();
_driver = spr.LaunchURL("Firefox");
seleniumContext.WebDriver = _driver;
}
public void GivenSetTheServiceTo(string serviceId)
{
When("UK_Select a Service from the option "+serviceId);
Then("UK_The Services is changed to the one selected " + serviceId);
}
Not sure, which is correct way of doing it? Trying to figure it out from Reusable steps point?The latter one is not advised as we need to change the type of browser to launch at multiple place.

WCF RIA Services DomainService error: ContractDescription has zero operations; a contract must have at least one operation

I am developing a small instant messaging application that makes use of few DomainServices on the server side. Trying to access the domain service URL, I encounter the following error:
"ContractDescription 'AppInitService' has zero operations; a contract must have at least one operation".
The domain service Url is this one:
http://givemeword.net/chat/Services/IM-Chat-UI-Web-DomainServices-AppInitService.svc
You can find the domain service class below:
namespace Chat.UI.Web.DomainServices
{
[EnableClientAccess()]
public class AppInitService : DomainService
{
private System.Security.Principal.IPrincipal _user;
private readonly Chat.UI.Web.Services.AppInitService _appInitService;
public AppInitService()
{
_appInitService = new Chat.UI.Web.Services.AppInitService();
}
public InitUserSettingsDTO InitUserSettings(Guid userId)
{
var initUserSettingsDTO = new InitUserSettingsDTO();
return initUserSettingsDTO;
}
}
}
As you can see, I am using a complex type as the return type of the only function of the domain service.
What I can not figure out is why on my testing Windows Server 2012 (not a development machine, just a virtual machine used for testing) or on my development machine everything runs without any problem, but on the hosting account it raise the error above.
Does anyone has any idea about this?
Thank you
Try adding the [Invoke] attribute to your InitUserSettings method:
[Invoke]
public InitUserSettingsDTO InitUserSettings(Guid userId)
{
var initUserSettingsDTO = new InitUserSettingsDTO();
return initUserSettingsDTO;
}
Make sure your web.config is set up as described here: http://msdn.microsoft.com/en-us/library/ff426912(v=vs.91).aspx
Being exasperated with this strange situation and the low support I received from the web hosting company, I have tried the same thing with another web provider. As I was thinking, it was working this time with no problems, so my assumption that the original provider had poor support for WCF RIA Services (or maybe other unidentified problem) was correct.

How to ping my website in Azure?

I wrote a Windows application to ping my website each 5 minutes to control whether it is UP or DOWN at the moment. it was working in our network and in our test server but our live environment is in Azure and it doesn't allow me to ping that web site.
What can I use instead of Ping to control my website in Azure? and how?
Use HttpWebRequest and HttpWebResponse and remember to Dispose the objects you create. In particular the response stream of HttpWebResponse.
HttpWebResponse res = req.GetResponse() as HttpWebResponse;
using (Stream respStream = res.GetResponseStream())
{
respStream.ReadByte();
respStream.Close();
}
I would suggest you take it outside of your own infrastructure. Mainly because ping'ing something can give you very limited information anyway. What if the role is up and running but your website is actually crashing with an exception? What if you have multiple instances of your role, one of which is down, and your ping request doesn't say anything is wrong?
Use something like Pingdom:
http://www.pingdom.com
It'll allow you to do a few things, that are probably not possible (or not easy) to do with your own 'inhouse' solution. Such as transaction monitoring (similar to very basic UI tests, have a user log in and click around for instance), multiple ways of alerting (even Twitter alerts) and multiple different request locations (it may work in the UK, but does it work when accessing it from France?).
Services like this were created for this sole purpose. You need to define when you believe your website to "be up" or "be down". Is it when it responds to ping's? Is it when your login page displays OK? Is it when your admin page displays OK?
I used HttpWebRequest and HttpWebResponse instead of Ping, but after 3 times the program freezes for some reason. I put everything in a try...catch block but it does not throw any exception either, only freezes.
try
{
var myRequest = (HttpWebRequest)WebRequest.Create(url);
var response = (HttpWebResponse)myRequest.GetResponse(); //After third time it freezes here
if (response.StatusCode == HttpStatusCode.OK)
{
labelResult.Text += TxtIPAddress.Text + " is Available " + " " + System.DateTime.Now.ToString() + " " + Environment.NewLine;
}
else
{
labelResult.Text += TxtIPAddress.Text + " is Unavailable " + System.DateTime.Now.ToString() + " " + Environment.NewLine;
}
}
catch (Exception ex)
{
labelResult.Text += TxtIPAddress.Text + " is Unavailable " + System.DateTime.Now.ToString() + " " + Environment.NewLine;
}
Another monitoring tool which is more complex is PRTG
It provides a number of monitors and is free for so many sensors you wish to monitor.
This way you can monitor not just a sites existence but whether a web service for a specific call returns, a SQL query. The possibilities are almost endless.

Silverlight WCF RIA Services Dynamically Change Connection String

We have a Silverlight application which uses WCF RIA Services and Entity Framework 4.1 to connect to a database.
At the moment, the connection string is supplied, as standard within the web.config and this all works successfully.
However, I now want to be able to change the connection string dynamically at runtime based on amongst other things, the user logged in.
I've found some other posts which hint at doing this, but they are using ObjectContext whereas we are using DbContext within the System.Data.Entity namespace and also the DbDomainService class.
In order to compensate for this I have overidden the CreateDbContext() method within my DbDomainService implementation as follows:
protected override CoreContext CreateDbContext()
{
dbServer = null, dbName = null;
httpCookie = System.Web.HttpContext.Current.Request.Cookies["DBServer"];
if (httpCookie != null)
{
dbServer = httpCookie.Value;
}
var cookie = System.Web.HttpContext.Current.Request.Cookies["DBName"];
if (cookie != null)
{
dbName = cookie.Value;
}
if (dbServer == null && dbName == null)
{
return new CoreContext();
}
string connStr = "Data Source=" + dbServer + ";Initial Catalog=" + dbName + ";Integrated Security=true";
return new CoreContext(connStr);
}
This works successfully the first time the Silverlight application is loaded, however, on all subsequent loads, the same connection as established initially is used despite changing the values being substituted into the connection string.
The only way to get the connection to be changed seems to be to recycle the application pool in IIS and load the app again.
Am I doing something wrong? Or is it not possible to have the DbDomainService change it's connection dynamically?
I'm thinking of the instancing model of your domainservice class. Have you tried a custom IDomainServiceFctory ? It permits you to decide when to create a new instance of them and is really simple to implement.
Take also a look at this post by Fredrik Normén.

Resources