xhr to service with windows authentication - xmlhttprequest

To access in browser web service using windows authentication I add the following:xhr.withCredentials= true;
Is it enough? Sometimes browser still shows windows asking for user win credentials. More details.
https://localhost:44386/api uses windows auth. Some users are allowed, some not - for test. Here is js code. Is it ok? Sometimes users still get dialog asking for teir windows credentials.
function send() {
const url = 'https://localhost:44386/api/values';
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open("GET", url);
xhr.onload = () => requestComplete(xhr);
xhr.send();
};

Related

How to remove/replace OneLogin cookies from browser programmatically

When I Login OneLogin with one user on the same system. it's working fine. but I will Login with another user on the same system, it shows me an error message due to the old user cookie saved on that system.
The below code is used to set OneLogin cookies.
function makeCors(session_token,link) {
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
var url = "https:domain_name_here.onelogin.com/session_via_api_token";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify({"session_token": session_token}));
};
Is there any way I can replace or remove OneLogin old user cookie from the browser programmatically?
To give the context we integrated the OneLogin with our React js application.

How to provide own login page if windows authentication get failed?

Currently i am working on one POC with Identity server4 where i have to show my own login page if windows authentication get failed(in this case i just want to show my own login page and avoid browser login popup .
My question is where to inject my own login page in code? and how application will know windows authentication get failed?If you check below code, first request to AuthenticateAsync always return null and then it call Challenge from else block which ask browser to send Kerberos token
and we achieve SSO but now i want to show my own login page if SSO fail.
My scenario is exactly similar like this
Anyone know how to achieve this?
private async Task<IActionResult> ProcessWindowsLoginAsync(string returnUrl)
{
// see if windows auth has already been requested and succeeded.
var result = await HttpContext.AuthenticateAsync(_windowsAuthConfig.WindowsAuthenticationProviderName);
if (result?.Principal is WindowsPrincipal wp)
{
var props = new AuthenticationProperties
{
RedirectUri = Url.Action("Callback"),
Items =
{
{ "returnUrl", returnUrl},
{ "scheme", _windowsAuthConfig.WindowsAuthenticationProviderName}
}
};
var id = new ClaimsIdentity(_windowsAuthConfig.WindowsAuthenticationProviderName);
var claims = await _userStore.GetClaimsForWindowsLoginAsync(wp);
id.AddClaims(claims);
_logger.LogDebug("Signing in user with windows authentication.");
await HttpContext.SignInAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme,new ClaimsPrincipal(id),props);
return Redirect(props.RedirectUri);
}
else
{
_logger.LogDebug("Re-triggered windows authentication using ChallengeResult.");
// Trigger windows auth
// since windows auth don't support the redirect uri,
// this URL is re-triggered when we call challenge
return Challenge(_windowsAuthConfig.WindowsAuthenticationSchemes);
}
}

Windows authentication fail with "401 Unauthorized"

I have a MVC client accessing a Web API protected by IDS4. They all run on my local machine and hosted by IIS. The app works fine when using local identity for authentication. But when I try to use Windows authentication, I keep getting "401 Unauthorized" error from the dev tool and the login box keeps coming back to the browser.
Here is the Windows Authentication IIS setting
and enabled providers
It's almost like that the user ID or password was wrong, but that's nearly impossible because that's the domain user ID and password I use for logging into the system all the time. Besides, according to my reading, Windows Authentication is supposed to be "automatic", which means I will be authenticated silently without a login box in the first place.
Update
I enabled the IIS request tracing and here is the result from the log:
As you can see from the trace log item #29, the authentication (with the user ID I typed in, "DOM\Jack.Backer") was successful. However, some authorization item (#48) failed after that. And here is the detail of the failed item:
What's interesting is that the ErrorCode says that the operation (whatever it is) completed successfully, but still I received a warning with a HttpStatus=401 and a HttpReason=Unauthorized. Apparently, this is what failed my Windows Authentication. But what is this authorization about and how do I fix it?
In case anyone interested - I finally figured this one out. It is because the code that I downloaded from IndentityServer4's quickstart site in late 2020 doesn't have some of the important pieces needed for Windows authentication. Here is what I had to add to the Challenge function of the ExternalController class
and here is the ProcessWindowsLoginAsync function
private async Task<IActionResult> ProcessWindowsLoginAsync(string returnUrl)
{
var result = await HttpContext.AuthenticateAsync(AccountOptions.WindowsAuthenticationSchemeName);
if (result?.Principal is WindowsPrincipal wp)
{
var props = new AuthenticationProperties()
{
RedirectUri = Url.Action(nameof(Callback)),
Items =
{
{ "returnUrl", returnUrl },
{ "scheme", AccountOptions.WindowsAuthenticationSchemeName },
}
};
var id = new ClaimsIdentity(AccountOptions.WindowsAuthenticationSchemeName);
id.AddClaim(new Claim(JwtClaimTypes.Subject, wp.Identity.Name));
id.AddClaim(new Claim(JwtClaimTypes.Name, wp.Identity.Name));
if (AccountOptions.IncludeWindowsGroups)
{
var wi = wp.Identity as WindowsIdentity;
var groups = wi.Groups.Translate(typeof(NTAccount));
var roles = groups.Select(x => new Claim(JwtClaimTypes.Role, x.Value));
id.AddClaims(roles);
}
await HttpContext.SignInAsync(IdentityConstants.ExternalScheme, new ClaimsPrincipal(id), props);
return Redirect(props.RedirectUri);
}
else
{
return Challenge(AccountOptions.WindowsAuthenticationSchemeName);
}
}
Now my windows authentication works with no issues.

Preserving cookies between sessions

I need to make sure that a browser is trusted every time the session is when performing Selenium script in Node.js (If the browser is not trusted by the server it resets in MFA with SMSes which I would like to avoid).
In Puppeteer it is simple by:
const browser = await puppeteer.launch({headless: false,
userDataDir: "./user_data"});
I would love to stay with puppeteer because of that but I have a dropdown selector on the page accessible only by name or xpath and page and page.select requires CSS selector:-(.
So I moved back to Selenium, but there I have this persistency problem:
At the end of a session I have:
var allCokies = await driver.manage().getCookies(); fs.writeFile("/Users/matnikr/Documents/scrape/selenium/cookies.json",JSON.stringify(allCokies), function(err){
if (err) {return console.log(err)}
console.log('file saved');})
A the begining I have:
driver = await new Builder().forBrowser('chrome').build();
var allCokies = JSON.parse(fs.readFileSync("/Users/matnikr/Documents/angular\ code/Aliorscrape/selenium/cookies.json","utf8"));
for (var key in allCokies){
await driver.manage().addCookie(allCokies[key])
}
await driver.get('https:*******/do/Login');
And every time it feels like "incognito" session is started. Browser is untrusted. Any help appreciated.
Did you try to do the same as you did with Puppeteer? I mean to load a profile. Because it's actually what you did by providing "./user_data" as a userDataDir value.
const { Builder } = require('selenium-webdriver');
const { Options } = require('selenium-webdriver/chrome');
function buildChromeDriver() {
const options = new Options();
options.addArguments('user-data-dir=./user_data');
return new Builder()
.forBrowser('chrome')
.setChromeOptions(options)
.build();
}
You can always verify the loaded profile by opening chrome://version in the browser:
driver.get('chrome://version');

API using SignalR with IdentityServer4 hangs on 3+ connections

My scenario is I have an API that implements SignalR and IdentityServer4. My client is a Vuejs SPA served from a .net-core app. After the vue client has the access_token I initiate the signalr connection and save it inside vuex store.
This is how I setup my connection:
var connection = new signalR.HubConnectionBuilder()
.withUrl(http://example.com + '/notifyHub',
{
accessTokenFactory: () => { return token }
}
).build();
connection.start()
.then(() => {
window.console.log("signalR connection successful")
})
.catch(function (err) {
return window.console.error(err.toString());
});
This is my API configuration of SignalR with IS4 Authentication
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = $"{_config["Server"]}";
options.RequireHttpsMetadata = _env.IsProduction() ? true : false;
options.ApiName = "api";
options.ApiSecret = "secret";
options.TokenRetriever = new Func<HttpRequest, string>(req =>
{
var fromHeader = TokenRetrieval.FromAuthorizationHeader();
var fromQuery = TokenRetrieval.FromQueryString();
return fromHeader(req) ?? fromQuery(req);
});
});
services.AddSignalR();
//sub claim is used from the token for individual users
services.AddSingleton<IUserIdProvider, UserProvider>();
And application
app.UseWebSockets();
app.UseAuthentication();
app.UseSignalR(routes =>
{
routes.MapHub<NotificationHub>("/notifyHub");
});
The client always establishes a successful connection, and all the live notifications work as expected.
Now to test the functionality I launch 2 clients, 1 from Chrome and 1 from Firefox, while the two clients are connected everything works.
As soon as try to connect a 3rd client (using Chrome Incognito or IE Edge), the signalr connection is successful but the API hangs for all 3 clients. If I refresh any of the clients the other 2 will resume working, if close one of the clients the other two resume working fine.
There is no valuable info in the logs on the client or the api side to indicate to what is happening.
My question is what can cause this issue and how to do I investigate?
Is this an issue of launching multiple clients from the same host, and will this occurs in production will it just block the single host launching the clients or all of the hosts?
EDIT
I changed from localhost to local IP 192...* to try connect from my mobile browser see if that changes anything, same thing happened, after 3rd client connects the API hangs, If I don't connect to the signalR hub by omitting connection.start() I can launch as many clients as I can without breaking.
I am hosting on local IIS at the moment and not IIS express.