ASP.NET Identity Cookie not being saved/set in subdomain - c#

Editing to add in extra details.
I have a web project that I effectively use as an authorization server (e.g. example.com). I then have a few web sites that sit as sub domains (e.g. sub1.example.com, sub2.example.com). I am currently unable to get the .AspNet.Cookies cookie to save on the subdomains when logging in to the authorization server. I can see the cookie come back in the response but it's not being set.
I have searched and tried various solutions such as setting the CookiePath and CookieDomain. I have verified the Machine Key in the Web.config file matches between all sites. This is currently how I am enabling Cookie Authentication:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
LoginPath = new PathString("/Account/Login"),
CookieDomain = ".example.com",
});
I have CORS enabled on the authorization server and I am able to receive the Bearer token when I log in, I just can't seem to get the cookie to be saved.
Thanks in advance.
Edit: I read somewhere that the ARRAffinity cookie could mess with things so I disabled that as well. I am still unable to see the cookie in the subdomain.
Edit 2: Adding the ajax call as requested in the comments (password and domain have been altered for consistency with the post):
$.ajax({
url: 'https://example.com/auth/token',
method: 'POST',
data: {
grant_type: 'password',
username: 'admin#example.com',
password: '************'
},
crossDomain: true
});

I'm going to take a shot at the answer here.
By default, when making cross-site ajax requests, browsers will ignore cookies. More information on this here.
To allow the use of cookies, you must set withCredentials to true in your requests, like so (more information here):
$.ajax({
url: 'https://example.com/auth/token',
method: 'POST',
data: {
grant_type: 'password',
username: 'admin#example.com',
password: '************'
},
crossDomain: true,
xhrFields: {
withCredentials: true
}
});
I've tested this locally and this should be enough if the only thing you need is to authenticate with example.com and then keep using the cookie while interacting with sub1.example.com.
If you also want to make a request with the cookie to example.com and do not want to have your responses ignored by the browser, according to this link you should make sure that example.com also returns the header Access-Control-Allow-Credentials: true.

Related

JWT auth with asp.net core to create token and store in http only cookies and angular to call method with header

I am new to JWT with basic idea of how it works. I have set the jwt token inside cookie from my web api.
Response.Cookies.Append("X-Access-Token", foundUser.Token
, new CookieOptions { HttpOnly = true }) ;
Now i am trying to call a web api get request which is marked as authorised from my agular application.
But inside angular i dont have a way to send the cookie. As per few documents i came to know that http only cookies are sent directly with our interference but i am not able to fetch the data with unauthorised error, which means that the token is not being used. I have not included the same in the get method as well. see below.
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet]
public async Task<ActionResult<IEnumerable<Invoice>>> GetInvoices([FromQuery]QueryParameters queryParameters)
{
return await _uOW.InvoiceRepository.GetInvoices(queryParameters);
}
Do i have to add some logic to read the cookie in backend? I didnt find any answer for this.
Please let me know if there is something missing.
Also inside angular i have not written any special code for calling this get. Is that required?
var headerForToken = new HttpHeaders({'Authorization':`Bearer ${sessionStorage.getItem("token")}`});
return this.http.get<any>(this.APIUrl+'Invoices/GetInvoices',{headers:headerForToken });
This is my current approach in which i am using local storage, but i really need to use the http only cookie.
If there is any link for solution or anything that would be really helpfull
Update 1: So we need to add a domain for this. I tried adding domain still it is not visible when i try to see the cookies.
Response.Cookies.Append("X-Access-Token", foundUser.Token
, new CookieOptions { HttpOnly = true, Domain = ".localhost:4200" }) ;

Sharing cookies between domain and a subdomain using IIS express

I'm trying to share a cookie between two ASP.NET mvc 6 apps :
The first one is a web api app and it should represent the main domain "localhost".
Second one is an empty mvc website client app, with one index.html that calls the web api via simple ajax. this app represents the subdomain "cleint.lohalhost".
For somereason, my browser is unable to set the cookie on the client app. Details below :
-Set cookie header generated by web api
Set-Cookie:mytoken=mytokenvalue; domain=.localhost; path=/; samesite=lax
-Ajax call :
$.get({
url: 'http://localhost:5004/api/values',
success: function (response) { console.log(response); },
error: function (error) { console.log(error); },
xhrFields: {
withCredentials: true
},
crossDomain: true
});
-And finally, the code that sets the cookie on the web api app :
[HttpGet]
public IEnumerable<string> Get()
{
Response.Cookies.Append("mytoken", "mytokenvalue", new CookieOptions() { Domain = ".localhost" });
return new string[] { "value1", "value2" };
}
-I use chrome browser if it's relevant.
I appreciate any kind of help, thank you.
It turned out my browser was still hungry for another '.' on the domain name, so I ended up replacing 'localhost' (on both domain names) with 'myapp.dev' and it worked.
It is also important to note that from the api side, I had to send the domain name cookie option with the value '.myapp.dev' instead of 'client.myapp.dev'

Get token and user details after token is issued in controller method

I am using Asp.net Identity for token based authentication in my web api application. The problem is I have to perform some operations after the token is generated and the user is authenticated and before the redirection to client side occurs.
I have a login page which uses /token token authentication . Once the token is issued i need to keep the user and token values in a session. [this session will be used to show online users.]
Client request
$('#btnLogin').click(function () {
$.ajax({
// Post username, password & the grant type to /token
url: '/token',
method: 'POST',
contentType: 'application/json',
data: {
username: $('#txtUsername').val(),
password: $('#txtPassword').val(),
grant_type: 'password'
}
});
Server side
[HttpPost]
public void Login()
{
OnlineUsers user = new OnlineUsers();
var users = (HttpContext.Current.Session["ActiveUsers"] as
List<OnlineUsers>) ?? new List<OnlineUsers>();
users.Add(user);
HttpContext.Current.Session["ActiveUsers"] = users;
}
I need to call this controller method after the token is issued and use is authenticated.
Is there any solution to this?
If you want to intercept generation of the token think you have to customize the aspnet identity behaviour
https://msdn.microsoft.com/en-us/library/microsoft.aspnet.identity.usermanagerextensions.generateusertoken(v=vs.108).aspx
With Web API using session is not a good approach, to keep user's information in client side you can use browser's localstorage. Once the user authenticated via your login api controller, you can return the user's required info as json to client, then you can keep it to browsers. Web API is by default stateless so i think session is not suitable with it, additional burden on the client. Storing session state on the server violates the stateless constraint of the REST architecture. So the session state must be handled entirely by the client.
Web API
[HttpPost]
public IHttpActionResultLogin()
{
OnlineUsers user = new OnlineUsers();
user=YourUserDetailsMethod();
return Ok(user);
}
Client:
$('#btnLogin').click(function () {
$.ajax({
// Post username, password & the grant type to /token
url: '/token',
method: 'POST',
contentType: 'application/json',
data: {
username: $('#txtUsername').val(),
password: $('#txtPassword').val(),
grant_type: 'password'
},
success: function(response){
window.localStorage.setItem('userInfo', response);
$('#UserName').val(window.localStorage.getItem('userInfo').UserName);
}
});

Nancyfx Request.Session not holding values on AJAX post

I'm quite new to Nancy so hopefully I'm just doing something silly here. I've got a nancy service which I'm posting data to like so:
$.ajax({
type: 'POST',
url: url,
data: JSON.stringify({
searchTerm: productSearchTerm,
pageSize: pageView.PageSize(),
selectedBrands: pageView.checkedBrands(),
pageNumber: pageView.CurrentPage(),
selectedCategories: pageView.checkedCategories(),
selectedGender: pageView.checkedGender(),
SelectedColours: pageView.checkedColour(),
saleItemsOnly: pageView.saleItemsOnly(),
selectedMinimumPrice: pageView.minPrice(),
selectedMaximumPrice: pageView.maxPrice()
}),
contentType: "application/json; charset=utf-8",
dataType: 'json'
})
.done(function (data) {
bindSearchResult(data);
})
.fail(function (a) {
console.log(a);
});
Then in the service I need to hold on to a bunch of string values for future requests from the user, which I'm doing like this:
private void AddListOfStringToIsSessionNull(string name, IEnumerable<string> data)
{
if (Session[name] == null)
{
Session[name] = data.ToList();
}
}
These seems to set the session variables and an "_nc" cookie is present when I inspect the page after it returns.
However if I then F5 the page the session items are all null again at the server.
I've ruled out are cross site posting as it's all on the same domain.
Could this be an AJAX thing? Seems unlikely as this seems a pretty standard thing to do.
Or can you not set it on a POST?
If so is there a way around this?
If someone could help I'd be forever grateful as otherwise I'm going to have to revert back to writing this in WCF which will make me hurl myself from the window :)
Thanks a lot.
Edit
Open a new incognito window in Chome I hit home page, no nancy cookie
present (which is correct)
Enter a search term which calls back over and AJAX post and grabs JSON, also pops a list of strings in the Nancy Session
Check cookie, a nancy one has appeared like so and the session value is correct on post back:
npTBnqPp99nLd5fU0%2btJbq%2fY%2bdf2UFWTaq5D28Az7Jw%3dzF8cIHNxTWX399sbmowjheho2S29ocpKs1TXD51BrbyPPNCeLfAcYqWhkRHqWdwKJNED5kuspllIjhI5rf2W6NKtf8xo68BlF5eLLgJxMtAxw2yD2ednEzUazq1XBt2Id77t5LE5tZVwkpRGDT5b9J0nQnr9zfzCOALXb2hQQGBPkMVyNNTO24pW1UC6Uda3B86LLYA02Jgy4G9DiT6KsutR3pSXO8AZFOlcmAEHbSSX9A8FAHaL ... etc.
I then search for a different search term which calls this bit of code:
--Session.DeleteAll();
The nancy session is re-populated with new data and returns back to the browser
However at this point the cookie has not been updated with the new value it is still as below:
npTBnqPp99nLd5fU0%2btJbq%2fY%2bdf2UFWTaq5D28Az7Jw%3dzF8cIHNxTWX399sbmowjheho2S29ocpKs1TXD51BrbyPPNCeLfAcYqWhkRHqWdwKJNED5kuspllIjhI5rf2W6NKtf8xo68BlF5eLLgJxMtAxw2yD2ednEzUazq1XBt2Id77t5LE5tZVwkpRGDT5b9J0nQnr9zfzCOALXb2hQQGBPkMVyNNTO24pW1UC6Uda3B86LLYA02Jgy4G9DiT6KsutR3pSXO8AZFOlcmAEHbSSX9A8FAHaL.... etc.
Is there anything else I need to do to solve this?
So my issue was me being a bit daft really, the implementation of the cookie stuff works well, however there were occasions when I was stuffing too much into the cookie and pushing it over the 4K cookie limit.
This meant that I was seeing some inconsistent behavior where sometimes the cookie worked nicely (the cookie was < 4K) where as for some search terms too much was being written into the cookie which meant either the cookie was never created or it was not overwriting the existing cookie.
So yes, my fault, but thought this answer might aid someone as silly as me trying to store the world in a cookie..
Right I'm off to write a session provider.

PageMethod 404 only on deployed website under XP/IIS 5.1. What security settings should I be aware of?

Been trouble-shooting this for a few days now and have basically run dry of leads.
Here's the code:
[WebMethod]
public static bool EnableEditMode()
{
bool successful = false;
try
{
GlobalSettings globalSettings = StateManager.GetStates<GlobalSettings>();
globalSettings.EditModeEnabled = true;
StateManager.SaveGlobalSettings(globalSettings);
successful = true;
}
catch (Exception exception)
{
_logger.ErrorFormat("Unable to enable edit mode. Reason: {0}", exception.Message);
}
return successful;
}
function EnableEditMode() {
$.ajax({
type: "POST",
url: "Dashboard.aspx/EnableEditMode",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
if( result ) {
$find(window.leftPaneID).expand(1);
$('#' + window.startEditButtonID).hide();
$('#' + window.finishEditButtonID).show();
}
}
});
}
Here's the error message:
Failed to load resource: the server responded with a status of 404
(Not Found)
http://localhost/csweb/Dashboard/Dashboard.aspx/EnableEditMode
Here's what I've tried:
Ensured that I am update-to-date with Windows Updates. Source
I removed 'EnablePageMethods = True' from my ScriptManager and started using a jquery ajax POST to execute the code. Nothing broke when I did this, the headers changed slightly, but nothing was fixed.
I tried using <%= ResolveUrl("~/Dashboard/Dashboard.aspx") %>, but the path did not change and I did not notice an effect, so I removed the code. Source
I went into my web.config file and removed the following according to Source:
<authorization>
<deny users="?"/>
</authorization>
I've ensured that the file is not ReadOnly and granted full-control permissions on the file and parent-folders for all relevant users on the system. (Not a live system so no worries.. just playing around).
I diff'ed the request headers between my working development and
non-working deployment -- I saw no differences in the request
headers.
I ran Permission Wizard on the website, indicated I wished to have the website security settings of a publicly-viewed website, and applied to all folders replacing current security settings. No effect.
Added .json // application/json MIME type, no effect, but I left it in since it seemed useful.
At this point I am suiting up to trek into the abyss of settings which is IIS. I am not very familiar with IIS 5.1, though. So, I am wondering if there are any specific spots I should start looking?
I found the reason, but I am working on figuring out how to fix it. I have an ASP.NET AJAX application integrated into an MVC solution. The MVC side of things is picking up the PageMethod and not handling it properly, but only under IIS 5.1:
[HttpException]: The controller for path '/csweb/Dashboard/Dashboard.aspx/EnableEditMode' was not found or does not implement IController.
Are you using ASP.NET MVC? You may need [AcceptVerbs ("POST")] on EnableEditMode().
Also, could you try just printing out (or debugging and viewing) the results of:
var pageURL = "<%= ResolveUrl("~/Dashboard/Dashboard.aspx") %>
var pageURL2 = "<%= ResolveUrl("~") %>

Categories

Resources