I am building self-hosted web server on this stack:
OWIN
Nancy
Web Api 2
And I am using Microsoft.Owin.Security.Cookies from Katana for forms-like authentication. I got Set-Cookie header in response, but cookie don't being saved and not being included in next request. So what's the problem? What I am doing wrong?
Owin startup:
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType = "GM",
CookieHttpOnly = true,
CookieSecure = CookieSecureOption.SameAsRequest,
CookiePath = "/",
CookieName = CookieAuthenticationDefaults.CookiePrefix + "GM",
CookieDomain = "localhost",
});
Controller code:
var context = Request.GetOwinContext();
context.Authentication.SignIn(new AuthenticationProperties()
{
IsPersistent = true
},
new ClaimsIdentity(new[] {new Claim(ClaimsIdentity.DefaultNameClaimType, user.Login)}, "GM"));
context.Response.Headers.Add("Location", new []{ "/" });
return Request.CreateResponse(HttpStatusCode.Found);
Response headers:
Cache-Control:no-cache
Content-Length:0
Date:Wed, 11 Sep 2013 11:11:23 GMT
Expires:-1
Location:/
Pragma:no-cache
Server:Microsoft-HTTPAPI/2.0
Set-Cookie:.AspNet.GM=AQAAANCMnd8BFdERjHoAwE_Cl-sBAAAABui2rBibE0yPXB0-v3C06gAAAAACAAAAAAAQZgAAAAEAACAAAAC1mQV3jGo_WAhMQ-hzsmzgkdbdCclWIAX-msbE0_12zQAAAAAOgAAAAAIAACAAAABuQjBg3EJIka151hvBgtlPGfQ2O_cwNI2VVh86dchTDXAAAAD21O9DnNk4yLU9eddVfY3bT9P1CEudNeLvwohkSTAQBP2onuIQfgl9F99Je5waPddckh2llD2kjftSMQPhzgE9vKm-_wE42hXhc9FIgfxpD5AdaeGatwpEcwDfGJJdpQnObX1pbjEFIXLVJxGm5qMUQAAAAC8AiFTaXmzrfRy4-jR6zqMmSKddzddmiBLGClAckWOy6W2YWdf50N2zhIj_MwN8-zi-B0tlv87pzAt-6RDZYZs; domain=localhost; path=/; expires=Wed, 25-Sep-2013 11:11:24 GMT; HttpOnly
I resolved the issue. It was because 'domain=localhost'. It seems to 'localhost' isn't valid value for domain parameter.
You could be encounting a similar issue to: Safari doesn't set Cookie but IE / FF does
Try setting the HttpStatusCode to HttpStatusCode.Ok
Some browsers will only accept cookies from a certain response code (like 200, 302).
Related
I'm using a django backend, and a CRAO frontend. I saved the jwt refresh token as a httponly cookie:
document.cookie = `refresh=${refresh_token}; SameSite=Strict; Path=/api/token/refresh; HttpOnly`;
Then to refresh the access token, I'm sending an axios request:
const response = await axios.post('/api/token/refresh/', { withCredentials: true });
But, in this case, the originally saved cookies don't get sent by axios. However, on removing the httponly attribute, the cookies do get sent, and everything works fine.
You did not set the cookie well in your django app. follow up this way to save it as httponly cookie:
response.set_cookie(
key=settings.SIMPLE_JWT["AUTH_COOKIE_REFRESH"],
value=token["refresh"],
expires=settings.SIMPLE_JWT["ACCESS_TOKEN_LIFETIME"],
secure=settings.SIMPLE_JWT["AUTH_COOKIE_SECURE"],
httponly=settings.SIMPLE_JWT["AUTH_COOKIE_HTTP_ONLY"],
samesite=settings.SIMPLE_JWT["AUTH_COOKIE_SAMESITE"],
)
I have a Cognito user pool configured with a SAML identity provider (ADFS) and I'm able to sign it as a federated user (AD) but sign out does not work.
Following the documentation, I make a GET request to
https://my-domain.auth.us-west-2.amazoncognito.com/logout?client_id=63...ng&logout_uri=http:%2F%2Fyahoo.com (using some public logout uri), from my client (an AngularJS 1.x app), and I get back a 302 with a Location header like
https://my-domain.auth.us-west-2.amazoncognito.com/login?client_id=63...ng&logout_uri=http:%2F%2Fyahoo.com
(In fact there I see 2 requests like the above).
When I log back in (thru ADFS) it does not prompt for my AD credentials, i.e. seems that I'm not logged out.
My user pool is configured as described here (see step 7), where the Enable IdP sign out flow is checked, which is supposed to log the user out from ADFS as well.
Any suggestions?
Thanks.
General
-------
Request URL: https://my-domain.auth.us-west-2.amazoncognito.com/logout?client_id=63...ng&logout_uri=http:%2F%2Fyahoo.com
Request Method: GET
Status Code: 302
Remote Address: 54.69.30.36:443
Referrer Policy: no-referrer-when-downgrade
Response Headers
----------------
cache-control: private
content-length: 0
date: Fri, 20 Apr 2018 21:31:12 GMT
expires: Thu, 01 Jan 1970 00:00:00 UTC
location: https://my-domain.auth.us-west-2.amazoncognito.com/login?client_id=63...ng&logout_uri=http:%2F%2Fyahoo.com
server: Server
set-cookie: XSRF-TOKEN=...; Path=/; Secure; HttpOnly
set-cookie: XSRF-TOKEN=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; Secure; HttpOnly
status: 302
strict-transport-security: max-age=31536000 ; includeSubDomains
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block
Request Headers
---------------
:authority: my-domain.auth.us-west-2.amazoncognito.com
:method: GET
:path: /logout?client_id=63...ng&logout_uri=http:%2F%2Fyahoo.com
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
authorization: Bearer eyJra...
cache-control: no-cache
origin: https://localhost:8443
pragma: no-cache
referer: https://localhost:8443/logout
user-agent: Mozilla/5.0...
This redirect happens whenever logout_uri parameter doesn't match exactly what's listed among Sign out URL(s) in AWS Cognito User Pools App client settings configuration.
Cognito allows logout with either logout_uri or with the same arguments as login (i.e. redirect_uri and response_type) to log out and take the user back to the login screen. It seems that whenever logout_uri is invalid, it assume the re-login flow, does this redirect, and then reports an error about missing login arguments.
As for SAML, I don't know, but guessing that it doesn't work because there was actually an error, just not properly reported.
The /logout endpoint signs the user out.It only supports HTTPS GET. It is working
Sample Requests - Logout and Redirect Back to Client
It clears out the existing session and redirects back to the client. Both parameters are required.
GET https://<YOUR DOMAIN NAME>/logout?
client_id=xxxxxxxxxxxx&
logout_uri=com.myclientapp://myclient/logout
Also make sure that Logout URL is same as SIGNOUT URL in AWS Cognito APP too.
for more information, refer AWS LOGOUT Endpoint
Finally I was able to fix this issue. I found the actual cause of the issue from the event viewer of my windows server 2012 R2. It says the following details about the failed sign out flow.
The SAML Single Logout request does not correspond to the logged-in session participant.
Requestor: urn:amazon:cognito:sp:userpoolid
Request name identifier: Format: urn:oasis:names:tc:SAML:2.0:nameid-format:persistent, NameQualifier: SPNameQualifier: , SPProvidedId:
Logged-in session participants:
Count: 1, [Issuer: urn:amazon:cognito:sp:userpoolid, NameID: (Format: , NameQualifier: SPNameQualifier: , SPProvidedId: )]
User Action
Verify that the claim provider trust or the relying party trust configuration is up to date. If the name identifier in the request is different from the name identifier in the session only by NameQualifier or SPNameQualifier, check and correct the name identifier policy issuance rule using the AD FS 2.0 Management snap-in.
The Error clearly says that the name identifier in the request is different from the name identifier in the session only by NameQualifier. I have corrected this error in the claim issuance tab of relying party trusts by adding the rule as below. The below rule replace the user#myadfsdomain to simply user when issuing the claim.
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = RegExReplace(c.Value, "(?i)^myadfsdomain*\\", ""), ValueType = c.ValueType, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent");
Besides this i have forgot to check in the enable signout flow in the cognito configuration which caused the problem. Logout started working seamlessly for me.
From documentation here
https://docs.aws.amazon.com/cognito/latest/developerguide/logout-endpoint.html
If you want
And your login url is like
"https://xxxx.auth.eu-west-1.amazoncognito.com/login?client_id=1234&response_type=token&scope=aws.cognito.signin.user.admin+email+openid+phone+profile&redirect_uri=http://localhost:3000/"
Then your logout url is like
"https://xxxx.auth.eu-west-1.amazoncognito.com/logout?client_id=1234&logout_uri=http://localhost:3000/";
Note the difference
login > login? and redirect_uri
logout > logout? and logout_uri
Those redirect / logout uri must match what you have configured inside Cognito.
If you don't do it right, you may get strange errors like
error=unauthorized_client
or
Required String parameter 'response_type' is not present
and who knows what else. :o)
My solution below is based on -
https://github.com/nextauthjs/next-auth/discussions/3938#discussioncomment-2165155
I am able to solve the issue with few changes-
in signout button upon clicking i will call handleSignOut
function handleSignOut() {
const clientId = 'paste your AWS COGNITO CLIENT ID';
const domain = 'paste your AWS COGNITO DOMAIN';
window.location.href = `${domain}/logout?client_id=${clientId}&logout_uri=http://localhost:3000/logout`
}
In Aws cognito-> app integration -> app client settings -> signout url
keep the following url-
http://localhost:3000/logout
in pages create a seperate page called logout and keep following code-
import { useEffect } from "react"
import { signOut } from 'next-auth/react'
export default function SignoutPage() {
useEffect(() => {
setTimeout(() => {
signOut({ callbackUrl: window.location.origin });
}, 1000);
}, []);
return (
<>
<div className="loader">
Loading..
</div>
<style jsx>{`
.loader{
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform: -webkit-translate(-50%, -50%);
transform: -moz-translate(-50%, -50%);
transform: -ms-translate(-50%, -50%);
}
`}</style>
</>
)
}
click signout it will log you out
#RequestMapping(value = "/logout", method = RequestMethod.GET)
public void logout(HttpServletRequest request, HttpServletResponse response) {
LOGGER.info("Logout controller");
try {
Cookie awsCookie = new Cookie("AWSELBAuthSessionCookie-0", "deleted");
awsCookie.setMaxAge(-1);
awsCookie.setPath("/");
response.addCookie(awsCookie);
Properties appProperties = new Properties();
applicationPropertyConfigurer.loadProperties(appProperties);
response.sendRedirect(appProperties.getProperty("logout.url"));
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate, max-age=0");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", -1);
request.getSession().invalidate();
} catch (IOException e) {
LOGGER.error("Exception in redirecting to logout.url URL", e);
}
}
//https:/domain_name.auth.us-west-x.amazoncognito.com/logout?response_type=code&client_id=&redirect_uri=redirect_uri_should_be_present_in_cognito_user_pool_Callback URL&state=STATE&scope=openid
How do I create a request that uses the Saml or Google IDP for authorization? My understanding is that if I put "acr_values=idp:Google" in my request then the request will be routed through my Google Idp path. Likewise if I put "acr_values=idp:saml2p" it should go through my Saml Idp. Is it a different path? Right now the request goes to localhost:98575/connect/token.
Here is my current Request:
POST /connect/token HTTP/1.1
Host: localhost:98575
Authorization: Basic SomethingEncrypted
Cache-Control: no-cache
Postman-Token: AGuid
Content-Type: application/x-www-form-urlencoded
grant_type=password&scope=customScope+openid+offline_access&username=actuallyfoobar#enterprisebeta.com&password=SomePassword&acr_values=idp:Google
Here is a snippet from my IdentityServer Starup.cs file:
public static void ConfigureIdentityProviders(IAppBuilder app, string signInAsType)
{
var authServicesOptions = new KentorAuthServicesAuthenticationOptions(false)
{
SPOptions = new SPOptions
{
EntityId = new EntityId("http://sp.example.com")
},
SignInAsAuthenticationType = signInAsType,
AuthenticationType = "saml2p",
Caption = "SAML2p",
};
authServicesOptions.IdentityProviders.Add(new IdentityProvider(
new EntityId("http://stubidp.kentor.se/Metadata"),
authServicesOptions.SPOptions)
{
LoadMetadata = true,
});
app.UseKentorAuthServicesAuthentication(authServicesOptions);
var google = new GoogleOAuth2AuthenticationOptions
{
AuthenticationType = "Google",
Caption = "Google",
SignInAsAuthenticationType = signInAsType,
ClientId = "767400843187-8boio83mb57ruogr9af9ut09fkg56b27.apps.googleusercontent.com",
ClientSecret = "5fWcBT0udKY7_b6E3gEiJlze"
};
app.UseGoogleAuthentication(google);
The acr_values with "idp:foo" is only used for the authorization endpoint, not the token endpoint. IOW, it's only used to automatically redirect the user in the browser to the indicated external identity provider.
I work on a app using angular.dart at the clientside and dart in the serverside.
I have write a login rest entrypoint and want to set cookies the header was in the response but the cookies are not set.
set-cookie:app-user=533c1470a2658184a7625d7d; Expires=Tue, 8 Apr 2014 9:15:47 GMT; Domain=.ballr.eu; Path=/
set-cookie:app-tokn=530fa71b615e168787a7cb5b5c589a5601065e1e3f921d4b770c784394de3a42; Expires=Tue, 8 Apr 2014 9:15:47 GMT; Domain=.ballr.eu; Path=/
I try to check my headers or my value set in cookies, but to my mind is good
headers :
request.response..statusCode=HttpStatus.OK
..headers.set(HttpHeaders.CONTENT_TYPE, 'text/plain: charset=UTF-8')
..headers.add("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, DELETE")
..headers.add("Access-Control-Allow-Headers", "origin, x-requested-with, content-type, accept")
..headers.add("Access-Control-Allow-Origin", "*");
cookies :
static setCookie(HttpRequest request, String key, String value, DateTime duration) =>
request.response.cookies.add(new Cookie(key, value)..path = '/'
..expires = duration
..domain = '.app.eu');
I follow some threads on stackoverflow and google groups and I think it's a problem of "withCredientals" a value I have set in an another projet (angular/Java) but I don't find this parameter on angular.dart.
Can you help me to find it or have you somes ideas?
Thank you for your help/time
I'm not sure if I understand you question correctly but maybe this is what you are looking for:
(on the client)
var request = new HttpRequest()
..open("POST", uri.toString(), async: true)
..withCredentials = true // seems to be necessary so that cookies are sent
EDIT
I missed that this is about Angular. This needs a slightly different approach.
If you use the Angular http service you have a parameter
class MyController {
Http _http;
MyController(this._http) {
_http.getString('someurl', withCredentials: true).then((e) => ...);
// or _http.request('someurl', method: 'POST', withCredentials: true).then((e) => ...);
}
}
I am working on a REST-based app that connects to Office365. The app will be available on multiple platforms, so I have created a portable class library to handle all the logic, including authentication. The PCL targets Windows Phone 7.1 and onwards, and includes the Microsoft HTTP Client Libraries (NuGet), which is required for Windows Phone 7.1 apps.
The last step of the authentication for Office365 is to get a FedAuth cookie from the site, and that is where I am having a problem.
The code I use to get the cookie is:
var handler = new HttpClientHandler();
handler.AllowAutoRedirect = false;
var newClient = new HttpClient(handler);
var newResponse = await newClient.PostAsync(host + "/_forms/default.aspx?wa=wsignin1.0", new StringContent(binarySecurityToken));
The 'host' variable is just the URL of the Office365 site, and the binarySecurityToken I got from previous requests. These things work equally well in all the apps: Whether I run the PCL code from the context of a Windows Phone 7.1 app, Windows Phone 8 app, Windows 8 app, or even a Console application, I am getting exactly the same response (see below), which contains the FedAuth cookie. This I have verified using Fiddler.
Then I try to get the cookie to reuse it on subsequent requests.
var cookieCollection = handler.CookieContainer.GetCookies(new Uri(host));
foreach (var cookie in cookieCollection)
{
if (cookie.Name.StartsWith("FedAuth"))
{
//TODO: Store the cookie.
return true;
}
}
This leads to the following result: On Windows Phone 7.1 the 'cookieCollection' variable only contains the cookie rtFa'. On the other platforms it contains all three cookies 'RpsContextCookie', 'rtFa', 'FedAuth'.
Windows Phone 7.1 differs from the other apps in that this is the only platform that actually uses the HttpClient from the NuGet package. The other platforms have a native HttpClient that is swapped in by the magic of PCL.
It seems likely that the problem is caused by the FedAuth cookie not having a domain. I have tried using .GetCookies(null), and different variations of .GetCookies(new Uri("something", UriKind.Relative)), which all result in an exception. I have also tried changing most of the properties of the HttpClientHandler without luck.
Has anyone encountered this problem, and perhaps solved it? Or just a suggestion on what I could try?
The response I get on the .PostAsync above is the same on all platforms, and according to Fiddler the raw response is:
HTTP/1.1 302 Found
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Expires: -1
Location: /
Server: Microsoft-IIS/7.5
X-SharePointHealthScore: 0
X-AspNet-Version: 4.0.30319
Set-Cookie: RpsContextCookie=; path=/
Set-Cookie: rtFa=+13jGMMp0A0V+driESaO30ixYclFCRjEvS2jMSwXPfQcrefiJvLEExxYu7V+1JZHM6X5JWeuL70jb3/N/Q/hUTwoAiC/XLJZ1QfERi4aUt8AAVF4ekcNyMdWnj65foDwPkhaV5z8whNSZQigBFD/2Vc1xMTH0ukHbS4cbtJO5U28/4g66vgIZg7dGpNOZg2jDt+HF3GSQ4/W+T1oS9/F5e+Pbwd0p8mqPhkGjL+M7IptmkeHoIqVcS4Ps25dM6q1AniLiv/3NujYmrQjseaEYZ2aaCfc7ZHX7LygBZm8KsoGNyTYRPmC+hZ7tsDq6wfto+xVpX1scggsU0+Qty3DPWUiwy1bBy8JR0znFG0+eDt9uBOQzqfOSjVvd8WNIKUFIAAAAA==; domain=sharepoint.com; path=/; HttpOnly
Set-Cookie: FedAuth=77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48U1A+RmFsc2UsMGguZnxtZW1iZXJzaGlwfDEwMDMwMDAwODc5MTUwMGVAbGl2ZS5jb20sMCMuZnxtZW1iZXJzaGlwfHRtakB3aWxkY293Lm9ubWljcm9zb2Z0LmNvbSwxMzAzNDIwOTYxNDAxMTIxMzMsRmFsc2UsV2lSQjlUVTdOSTk0MUpKRWZ5d1JDNTFPYUphMVpWNkJqWWdaVGM3MU00U3lqL2VkTnF6dVJpbXdEMnpEWk9oR1lybkFsNnpWb3M4V0FBZDk1VVYrZkt5dlkwQ3dqRTlyaEhEc256bkZUeENoODU1Rm1JZmxoYVBkMTFQS2VjWnFJN0N4OUxUOHk4enZDaVNUTGNQMzR2K3NOeHk1YXBMZ2NIWDNHR3JMcG1Ic24rQzAzUkUzakNDQWhma2F3RVRQbk03R3JycVk5amJseHJmNVNhNHZxMk91NlN1cGszZnpQMUZQTzJBc1UrRXZvSDgvWTllR2Y3c2x2dStvMnVlN3hZLy9VQ1lYU1U4b3AzckZ6c2laK0wwN1NrUnZYMTZjVklUVVZJZ0x6TGIxaTJLd2lwNGp6RHgwRFdmVWF0Rk42UVFaNWhHRzMyOHRJZjI2RXo4YldnPT0saHR0cHM6Ly93aWxkY293LnNoYXJlcG9pbnQuY29tLzwvU1A+; path=/; secure; HttpOnly
SPRequestGuid: 5bb2689c-d7c5-c07c-4890-ee32437f15f5
request-id: 5bb2689c-d7c5-c07c-4890-ee32437f15f5
SPRequestDuration: 125
SPIisLatency: 2
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 16.0.0.2308
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
P3P: CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI"
Date: Thu, 09 Jan 2014 21:46:53 GMT
Content-Length: 118
<html><head><title>Object moved</title></head><body>
<h2>Object moved to here.</h2>
</body></html>
I found an answer of kind here: Accessing HTTPOnly cookies from Windows Phone 8/PCL.
Reading the post I realized that I made an error above: I was not getting the 'rtFa' cookie in the Windows Phone 7.1 app, but the 'RpsContextCookie'. The cookies I couldn't access were both marked with HttpOnly.
I also realized that I don't need to access the cookies directly. Instead, I could just reuse the handler.CookieContainer. So my code now looks like this:
var handler = new HttpClientHandler();
handler.AllowAutoRedirect = false;
var newClient = new HttpClient(handler);
var newResponse = await newClient.PostAsync(host + "/_forms/default.aspx?wa=wsignin1.0", new StringContent(binarySecurityToken));
this._cookieContainer = handler.CookieContainer;
return true;
this._cookieContainer is just a class-scoped field for storage of the cookie container. Then, once I am authenticated and I do the requests that are the actual purpose of the app, I do the following:
var handler = new HttpClientHandler(){ CookieContainer = this._cookieContainer };
var client = new HttpClient(handler);
var response = await client.GetAsync(host + "something");
So the bottom line is: I can't access the HttpOnly cookies - but I don't need to. I just reuse the cookie container, and the cookies are automatically included in the next request.
This works both in Windows Phone 7.1 apps, Windows Phone 8 apps, Console applications etc.