Sharing cookies between domain and a subdomain using IIS express - c#

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'

Related

403 Forbidden/500 Internal Server Error after deploying .net core api AWS Serverless application

Created a .net core AWS Serverless Application.
Cognito is used to authenticate.
Users and App clients have been configured.
When I ran the solution locally it worked fine (bearing in mind it
was http).
When I published using the publish wizard and hit the new url with
postman (https://myendpoint/Prod) I immediately get:
{
"message": "Forbidden"
}
I can only guess that it is to do with http / https here.
Controller for Authentication:
public class AuthenticationController : Controller
{
[HttpPost]
[Route("api/signin")]
public async Task<ActionResult<string>> SignIn(User user)
{
var cognito = new AmazonCognitoIdentityProviderClient(RegionEndpoint.APSoutheast2);
var request = new AdminInitiateAuthRequest
{
UserPoolId = "ap-southeast-2_MYPOOLID",
ClientId = "MYCLIENTID",
AuthFlow = AuthFlowType.ADMIN_USER_PASSWORD_AUTH
};
request.AuthParameters.Add("USERNAME", user.Username);
request.AuthParameters.Add("PASSWORD", user.Password);
var response = await cognito.AdminInitiateAuthAsync(request);
return Ok(response.AuthenticationResult);
}
}
Startup.ConfigureServices
services.AddSingleton<IAuthorizationHandler, CognitoGroupAuthorisationHandler>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = "https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-2_MYPOOL",
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateLifetime = true,
ValidAudience = "MYKEY",
ValidateAudience = true
};
});
EDIT #1
It appears I resolved the forbidden msg but am now getting a 500 error.
Postman yields: 500 Internal Server Error
Testing with API Gateway (Api Gateway->Resources-> /{proxy+}->Any->Test->Post)
Method: POST
Proxy is set to : /api/signin
Request Body:
{
"username": "xxx",
"password":"yyy"
}
yields:
{"Strict-Transport-Security":"max-age=2592000","ErrorType":"AmazonCognitoIdentityProviderException","X-Amzn-Trace-Id":"Root=xxxxx;Sampled=0","Content-Type":""}
Ok - This may help someone at some stage
The initial "Forbidden" error was not actually a permissions issue. When the API is deployed via the wizard it actually adds the "staging" directory at the end of the URL. I did not add this to my postman request. It's simple to do and overlook. It's a bit misleading - It should really be a 404.
The second part (Edit #1) 500 Internal Server error. There's no real "easy" way to solve this except for enabling cloudwatch logs against your API and then scouring.
Follow this YouTube video on how to set this up:
https://www.youtube.com/watch?v=R67huNjk88w
After looking through the logs I found that it was an permissions issue:
Amazon.CognitoIdentityProvider.AmazonCognitoIdentityProviderException: User: arn:aws:sts::xxxxx:assumed-role/xxx-AspNetCoreFunctionRole-xxx/xxx-AspNetCoreFunction-xxxx is not authorized to perform: cognito-idp:AdminInitiateAuth on resource: arn:aws:cognito-idp:ap-southeast-2:xxxx:userpool/ap-southeast-2_xxxxx --->
Credit goes to the following article:
https://medium.com/#fcavalcantirj/tutorial-aws-api-gateway-cognito-userpool-8cc5838eac0
Step 2.2.4.4 Specifically. As I found the Visual Studio Wizard takes care of pretty much everything else, I just needed to add these extra policies.
{
"Version":"2012–10–17",
"Statement":[
{
"Effect":"Allow",
"Action":[
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource":"arn:aws:logs:*:*:*"
},
{
"Effect":"Allow",
"Action":[
"cognito-identity:*",
"cognito-idp:*",
"cognito-sync:*",
"iam:ListRoles",
"iam:ListOpenIdConnectProviders",
"sns:ListPratformApplications"
],
"Resource":"*"
}
]
}
Policy is created and applied by:
Services->IAM->Policies->Create Policy->Json->
Paste the policy above. (If you get an error about malformed JSON, use the existing JSON in the JSON box and copy only the content between curly braces under Statement from the above policy - including the curly braces themselves obviously).
{
"Version": "2012-10-17",
"Statement": []
}
Go to Review Policy and Finish off creation
Go to Roles
Click on the AspNetCoreFunctionRole User that was logged and shown in Cloudwatch Log
Under Permissions Click Attach Policies
Type in the name of your newly create policy
Post to your login page and Voila

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

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.

ArcGIS portal - login in code without prompt

I am trying to write a program that will login a user programatically into a ArcGIS portal.
Here is my scenario:
User logs in to application A, user clicks a link to the ArcGIS portal - I do not want them to have to login to the portal when they click that link because that have already logged into application A.
SO
I would like:
User logs in to application A, user clicks a button containing the portal link as an argument and redirects to application B. Application B logs the user into portal and redirects them with the link from application A - the user is redirected without being prompted to login.
The portal is using portal tier authentication and I am using javascript but I could also use .NET/C#
UPDATE:
My current solution looks like this:
var url = "https://PORTAL_DOMAIN/portal/sharing/rest/generateToken";
var redirect = "https://PORTAL_DOMAIN/portal/home/webmap/PLACE_I_WANT_TO_REDIRECT_TO";
var params = {
'username': "username",
'password': "password",
'client': "referer",
'referer': redirect,
'expiration': 60,
'f': 'json'
};
$.post(url, params)
.done(function (data) {
var tokenHolder = JSON.parse(data);
var token = tokenHolder.token;
$('body').append(token);
document.cookie("esri_auth", token);
window.location = redirect;
});
This code gets me a token from the rest service - I try to store it has a cookie but it doesn't persist.
I have also tried using a C# web request and a credential cache to generate the credentials but I didn't save the code I was using.
SOLVED IT:
Okay, so my original post was not far off from what I needed. My missing link was the cookie formatting and properties.
Also its important to mention that you cannot run this locally but you have to has access to the portal server and it only works once published out.
IN THE CODE BELOW:
ENCODED COOKIE - is an URL encoded json object. I signed into my portal and just copied the cookie format (using chrome dev tools) and concatenated the generated token into the cookie and redirected. ALSO I had to set the domain,expire, and path properties of the cookie.
var url = "https://PORTAL_DOMAIN/portal/sharing/rest/generateToken";
var redirect = "https://PORTAL_DOMAIN/portal/home/webmap/PLACE_I_WANT_TO_REDIRECT_TO";
var params = {
'username': "username",
'password': "password",
'client': "referer",
'referer': redirect,
'expiration': 60,
'f': 'json'
};
$.post(url, params)
.done(function (data) {
var tokenHolder = JSON.parse(data);
var token = tokenHolder.token;
var domain = ".PORTAL_DOMAIN";
document.cookie = "esri_auth=ENCODED COOKIE;expires=Session;domain=" +domain + ";path=/;secure";
window.location = redirect;
});

HttpContext Session resets after client side request only

Overview
I have an ASP.net core API that has one controller. There are two relevant methods. The first Is LoginGet, which takes in a long token through the URL. Once the token is parsed through a separate core authentication API, the long token is stored like so:
Request.HttpContext.Session.Set(longToken, Encoding.UTF8.GetBytes(stringResult));
Then, the API generates a GUID for the user to store in session storage. After the user retrieves that GUID, they can pass it through GetAll, which filters through a database only picking out the data that correlates to the user that passed through the GUID. That means the API has to take the GUID, and compare it to the long token that was stored in session at the LoginGet request.
The Good
It all works when I hit these request from my localhost. Here is the series of request I make:
First I hit LoginGet():
http://localhost:5000/api/picker/login?token=ljadsljdaslkjsdfljkljgsdfkjgfFSDDFSsakgfjhdfkhdsfFDAS/asdfkjhdsf+sfdhjkfdsa
That returns a GUID like this:
58fa0fec7726433da47dce966b313c69
Then I hit GetAll():
http://localhost:5000/api/picker?ath=58fa0fec7726433da47dce966b313c69
That returns my json data
The Bad
The above example works! So what's wrong? When I do those exact same request (but with a different random GUID) from my Angular 2 application which is being served locally on a different port (http://localhost:3000/), LoginGet() is successful and returns a new GUID, but when I make the second request, GetAll(), immediately after the first, while debugging, I see that the Session has changed on the API, as if I were doing the second request from a new browser, or I just cleared my cookies.
This was not the case when I was simply making these calls from the browser, myself, manually. I have my request being console logged on the front end, and I get the exact same request URLs as I explained above.
I feel like this has to be an issue with how I am making the request on the front end. But I don't see how that could be the case. Even with routing, my session should remain the same.
Here are the two request methods relevant to this issue (Angular 2)
public Get(): Observable<{}> {
let newQuery = 'http://localhost:5000/api/picker?ath=' + sessionStorage.getItem('user.token');
return this.http.get(newQuery).map(this.extractData)
.catch(this.handleError);
}
public GetLogin(longToken: string) {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
let body = JSON.stringify({ password: longToken });
return this.http.get('http://localhost:5000/api/picker/login?token=' + longToken);
}
The order of operations for those request go like so:
1. A longToken is given by the user
2. The long token is passed to GetLogin(longToken)
3. The result is returned and immediately subscribed to.
4. On success, the generated GUID from the API is set in sessionStorage
5. The appilication routes to a different component (this.router.navigateByUrl('/library?pvy=me'))
6. After routing, in library component ngOnInit, Get() is called and uses the GUID stored in sessionStorage.
7. The result is immediately subscribed to in the library component.
That's It
What could be happening in my Angular 2 App that changes the session on the API? Or am just completely lost on how Sessions work in .net core?
What I found out is that when hitting the API externally, from the browser Address bar, Headers were being generated automatically. Which means the cookies from the session could be stored there. When I was calling my Get() method from the angular 2 App, I wasn't adding a header to my request, so the API assumed it was a new session.
My new Get() method on the angular 2 app:
public Get(): Observable<{}> {
let newQuery = 'http://localhost:5000/api/picker?ath=' + sessionStorage.getItem('user.token');
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get(newQuery, options).map(this.extractData)
.catch(this.handleError);
}

URL in $.post with multiples websites

I have a JavaScript to fill my address
$.post('/Endereco/getEnderecos', { CardCode: dado }, function (data) {
if (data) {
(...)
My problem is: if i publish my website in 'localhost',works,but if i publish my website in "localhost/site" not work, is the same to "www.mydomain.com" and "www.mydomain.com/site"
My website is Development in C# asp.net MVC3 IIS7
i have tried use the javascript to get the host, but not work
Thanks
You have a leading slash in your address /Endereco/getEnderecos, this will cause the browser to navigate to the root of the current host and then the URL you have provided.
For example, posting to /somePage from a page at www.mysite.com/folder/subfolder/page will post to the url www.mysite.com/somePage.
To rectify this, remove the slash from before Endereco, so your post looks like this:
$.post('Endereco/getEnderecos', { CardCode: dado }, function (data) {
if (data) {
(...)
In response to your comment, you could instead use the .. notation which means "go up a folder":
$.post('../../Endereco/getEnderecos', { CardCode: dado }, function (data) {
if (data) {
(...)
From localhost/order/Endereco/getEnderecos your resulting URL would be localhost/Endereco/getEnderecos, as we used two .. components, it has gone up two folders instead of one.
I was looking for some kind of tutorial on relative URLs and found this page: http://www.webreference.com/html/tutorial2/3.html. It might help you to better understand HTTP URLs =]

Categories

Resources