Problem with automatic Login into subdomain after signup -- Rails 3, Authlogic, Subdomain-fu - authlogic

I am using rails 3.0.0.beta3 to implement authlogic and subdomain-fu. And, I have a problem with automatic login into subdomain after signup.
The scenario is :
I have a signup form where an account and an admin user for that account are created simultaneously. Each time a new account is created, a separate subdomain is assigned to that account.
When the form is submitted, I expect the user to be redirected to
"user-sub-domain"."app-domain".com with the session for that sub-domain created automatically.
Currently, although the user is redirected to the corresponding subdomain, the session is not created. I think that the session is created only for the app-domain and when it is redirected to the subdomain, it doesn't find the session and thus, prompts the user to login again.
However, second-time login works fine.
I tried something like
config.action_controller.session = { :domain => '.dummy.localhost' } in development.rb. But, it doesn't seem to work. It still shows up the login form.
I would appreciate your help.
Thanks.

Look at "config/initializers/session_store.rb":
Rails.application.config.session_store :cookie_store, {
:key => 'app_session',
:domain => '.example.com' }

Related

Cancelling new user signup in Azure AD B2C redirects to sites home page, produces "AuthorizationFailed" error

I have a Blazor Hosted WASM application, and am using Azure AD-B2C to secure it. If a user who is not logged in tries to access any site on the page, they are directed to our b2c login page, as they should be, and if they supply a good username and password they are allowed to view the site. So far so good. However, if the user clicks on "Sign up now", and then cancels the signup process instead of providing a new username, password, and e-mail address, then they are redirected to the site's landing page (as if they had provided a good username and password), which fails to redirect them back to the b2c login page and produces a console message reading "info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user"
The documentation suggests that I access the app's manifest and set the allowPublicClient attribute to null or true to address this problem. I have done this, and the problem persists. Why isn't the user being redirected back to the B2C login page in this case, when they normally would be if they try to access any page on the site (including this landing page) in other cases?
When the user cancels and get redirected back to the landing page, it returns an specific error code in the url (eg: AADB2C90118) in the return redirect url (In some cases it only flashes quickly because Angular removes the query string after the redirect).
You need to listen to this and handle it. You can handle it manually by parsing the return url but if you use msal.js on client side you can listen to this and start the reset password flow.
this.broadcastService.subscribe("msal:loginFailure", (error) => {
console.warn("msal:loginFailure", error);
// Check for forgot password error
// Learn more about AAD error codes at https://learn.microsoft.com/en-us/azure/active-directory/develop/reference-aadsts-error-codes
if (error.errorMessage.indexOf("AADB2C90118") > -1) {
alreadyRedirecting = true;
this.msalAuthService.loginRedirect(
b2cPolicies.authorities.resetPassword
);
}
});
The above example is for when the user clicks on forgot password link and get redirected back, so you will need to find the error code that applies to you.

Authorize a WordPress site and a React app with a web hook and token?

Problem: The client is using MemberPress/Wordpress as their main platform. The users are being managed there. I built a React app to coexist with the Wordpress platform.
What I have done: Memberpress has webhooks. So when a user logs into WordPress I hook into that action with a node server that inserts the user into a custom database and I generate a token so that the user can access the nodes the user owns within my infrastructure.
module.exports = (req, res) => {
const { id, email } = req.body.data;
request(
"https://api.graph.cool/simple/v1/73289237283967",
mutation,
{
wpId: id,
email
}
).then(data => {
res.json({ status: "success" });
});
};
The above gets triggered every time a user logs in. This executes a graphQl mutation that has a custom resolver that checks if the user with that wpId exists. If not it will create a new user. Then it generates a node token https://github.com/prisma-archive/graphcool-templates/blob/master/auth/email-password/src/signup.ts and sends back in the response.
Once I obtain the token I can make requests on the user.
Problem: I am not sure how I can connect the two. I have to redirect the user to the wordpress login page. The login action triggers the event, and a token will be generated. I am not sure how I can store that token in an efficient way that can then be sent back to my app.
My thought would be to write a small plugin inside WordPress to handle the response of the hook and store the token in local storage within WordPress. Then whenever the user clicks to go to the app I can put the token in the URL (feels slightly weird and cant directly go to the URL). I am out of any other thoughts and would appreciate a nudge in the right direction.

How do I properly prevent mulitple active sessions in ASP.NET Identity 2.2.1 without affecting password change behavior?

I have a requirement to eliminate multiple active sessions from being allowed on our site.
It is my understanding that to do this you can manipulate the validateInterval parameter of the OnValidateIdentity property of the CookieAuthenticationProvider as below:
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(0), //Changed from default of 30 minutes
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
I changed the default value from 30 minutes to 0 for testing and it works as anticipated. If I log in to a second browser the next action taken in the first browser redirects me to the login page.
I also allow users to change their password whenever they want (after login). With the validateInterval property at zero, the user is logged out immediately after submitting a password change. They then log back in with the new password and are able to use the site as normal.
If I change the validateInterval parameter value to say 10 seconds, the user is allowed to continue the current session after submitting a password change for 10 seconds and then is redirected to the login page.
Inside the ChangePassword action of the ManageController class the default code that runs after a successful password change is this:
if (result.Succeeded)
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user != null)
{
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
}
return RedirectToAction("Index", new { Message = ManageMessageId.ChangePasswordSuccess });
}
I thought that the line SignInManager.SignInAsync would keep the user's session going even through a password change (from Logout User From all Browser When Password is changed), but it seems to be controlled additionally by the validateInterval parameter.
If I wanted to allow a user to change their password during an authenticated session without forcing then to login again, could I do this with ASP.NET Identity and still control multiple active sessions? Is there a better way to control multiple active sessions without changing the validateInterval parameter (from Prevent multiple logins)?
Thank you for your help. To clarify, if this behavior is by design, I am fine with it. I just want to understand what is going on so I can defend the behavior to my boss if needed.
Edit:
I failed to mention that I also update the security stamp directly prior to the sign in via SignInManager in the Login action.
Doing what you're doing does not prevent multiple active sessions. I'm also assuming by "sessions" you're talking about multiple authentications by the same user account. Multiple active sessions, in the truest sense, is an entirely different discussion. That said, the cookie that's set to maintain the user's "authenticated" state is client-specific. If I log on from my desktop computer and from my mobile device, or even from both Chrome and Internet Explorer on the same computer, those are all different cookies, unaffected by other cookies that may have been set on other devices or browsers.
The only way you could truly prevent this is to somehow mark the user as "logged in" server-side (i.e. a column on your user table for example). Then, before authenticating them anywhere else (basically in your sign in post action), you would check their user account for this flag. If it's already set, then you would refuse to log them in again until they first log out on the original device/browser. Obviously, your log out action would have to then unset this flag, so they would be allowed to log in again elsewhere.

Loging out of Azure Passport authentication Node js

I have a node js application in which we have used azure login with passport authentication.
I have successfully logged in using azure and the application is working fine.
But, when I logged out and give the url to a page - it checks for authentication and automatically go to that page without asking for login.
Once I logged in my url contains below query string
1. session_state
2. code
3. state
4. token
Log in Code:
app.get('/login', passport.authenticate('azuread-openidconnect', { failureRedirect: '/' }), function (req, res) {
res.sendFile(path.join(__dirname+'/index.html'));
});
Logout code:
app.get('/logout', function (req, res) {
req.session.destroy();
req.logout();
res.redirect('/');
});
When i logout the page redirects to my index page. Then when i give '/login' to the url it takes me to the page without going to logging in page
Please help to get out of this...
This issue is caused by the Authorization Code Grant Flow of OAuth 2.0. Something like that there are any session on Azure AD OAuth 2.0 service. It is not the problem of passportjs or expressjs.
We can have the following simple test, visit the authentication endpoint in browser, https://login.microsoftonline.com/common/oauth2/authorize?response_type=id_token%20code&client_id=<client_id>&redirect_uri=<redirect_uri>&response_mode=query&scope=openid
You will need to fill the email and password first, after you finishing the login flow, the second time you visit the endpoint, you will not longer need to fill the email or password anymore.
We can set the url param prompt to login in the authorize endpoint to force the users to re-authenticate every time.
You can refer https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx#code-snippet-3 for the details.
But in the azure passport oidcstrategy, we should modify the source code for add the param into the endpoint.
After you install the passport-azure-ad module, open the file /node_modules/passport-azure-ad/lib/passport-azure-ad/oidcstrategy.js, at Line 545 (more or less), you can find the following code snippet:
var params = {};
if (self.authorizationParams) { params = self.authorizationParams(options); }
params['response_type'] = config.responseType;
log.info('We are sending the response_type: ', params['response_type']);
params['client_id'] = config.clientID;
params['redirect_uri'] = callbackURL;
...
We can add the sentence params['prompt'] = 'login'; following the code snippet to add the support.
Any further concern, please feel free to let me know.
edit
Is there any way to prompt login only when i logged out...
I am not sure that do you mean, you want to check the user is authenticated when he visit login route, if is, do not prompt login flow?
If so, you can custom a middleware to check the authenticated. E.G.:
function checkAuthenticatedOnLogin(req,res,next){
if (!req.isAuthenticated()) {
return next();
}else{
res.send('do not need login');
}
}
app.get('/login',checkAuthenticatedOnLogin,
passport.authenticate('azuread-openidconnect',{ failureRedirect: '/login' }),
function(req, res) {
log.info('Login was called in the Sample');
res.redirect('/');
});
Logging out of your application does not mean the user is logged out of Azure. When a user logs out of your application you simply destroy the session your application has for said user. When they go to login again it will redirect them to Azure (where they're still logged, and where your application still has permission) which then instantly redirects back to your application with a token for that user. You would need to have the user log out of Azure to have them prompted again for their credentials.
1) I had this same problem, as passpor-azure documented I was executing this function to logout:
logout: function(req, res) {
req.logout();
res.redirect('/');
}
But Azure login session keeps active, so when I re-enter into my website, the autentication request will automatically be valid and no login page will be showned.
I tried #Gary Liu - MSFT suggestion to configure prompt:login option, but has #user3211705 commented, this makes login page reappear (even if I don't do logout and I have a portal.azure.com tab open), for instance when I restart my server (note: this isn't wrong, but when we are developing, one restarts the server all the time, and it gets annoying to login all the time)
2) Part of my solution came from this post:
Which suggest to invoke this url to logout user at Azure AD:
https://login.microsoftonline.com/<tennantid>/oauth2/logout
But only doing this didn't do the job for all situations.
If I have my website open in more than one window/tab browser, the user gets invalid in Azure AD by invoking this url, but I can keep using my website at the other tab (it seems like the user in that tab session keeps still active).
This is similar to have my website in one tab and on another tab with the portal.azure.com open, and do logout in portal.azure.com which invalidate my user at Azure AD.
So my final solution was a mix of both
logout: function(req, res) {
req.logout();
res.redirect('https://login.microsoftonline.com/<tennantid>/oauth2/logout');
}
This does logout my user in the request and invokes logout authentication in Azure AD.
One can still add a redirect uri at logout url param ?post_logout_redirect_uri=
/oauth2/logout?post_logout_redirect_uri=<your website>
Looking at the code for Azure xplat they don't seem to call an explicit logout function, instead they simply delete all of the relevant client side tokens.
If there are no local tokens you can't be logged in!

Azure ACS custom Identity Provider Single SignOut

I'm implementing my own identity provider based on Thinktecture code. Here is a strange behaviour of Azure ACS while using a single sign-out feature, it differ for google/live and for my own identity provider.
URL for sign-out (realm is really same as a site name):
mysite.accesscontrol.windows.net/v2/wsfederation?wa=wsignout1.0&wreply=http%3a%2f%2flocalhost%2fAdministration.Frontend.Web%2f&wtrealm=http%3a%2f%2flocalhost%2fAdministration.Frontend.Web%2f
Here is a pseudo-code for logout:
//clear FedAuth cookies
FormsAuthentication.SignOut();
FederatedAuthentication.WSFederationAuthenticationModule.SignOut(true);
//call Single SignOut
var signoutRequestMessage = new SignOutRequestMessage(new Uri(signOutUrl));
return Redirect(signoutRequestMessage.WriteQueryString());
Here is sample flow (i'm using private browsing plus Fiddler to see everything):
1) I'm logging into my application with google account.
2) click a logout, in result i get a page on ACS with a this code:
function on_completion()
{window.location = 'http://localhost/Administration.Frontend.Web/';}
<iframe src="https://www.google.com/accounts/Logout" style="visibility: hidden"">/iframe>
<iframe src="http://localhost/Administration.Frontend.Web/?wa=wsignoutcleanup1.0" style="visibility: hidden"></iframe>
Result: i'm logged out from my application and google.
3) Log to my identity provider, click logout, redirected to same URL on ACS as on previous step but now i get 302 result with redirecting to
https://localhost/IdentityProvider/issue/wsfed?wa=wsignout1.0&wreply=https%3a%2f%2fmysite.accesscontrol.windows.net%2fv2%2fwsfederation%3fredirectUrl%3dhttp%3a%2f%2flocalhost%2fAdministration.Frontend.Web%2f
Result: i'm logged out from my application and my identity provider.
4) try to use google again, sucessfully login by entering credential, but logout if failed. I'm logged out from application but not logged from google. And also i see that i don't get page with iframe but instead ACS again try to redirect me to
https://localhost/IdentityProvider/issue/wsfed?wa=wsignout1.0
(and then back to mysite.accesscontrol.windows.net and finally to my application)
Two main question:
Why calling ACS logout give me iframe page with additional
wa=wsignoutcleanup1.0 for google/live but 302 redirect to my
identity provider, may be i miss something in
FederationMetadata.xml?
It looks like ACS after step 3 don't
understand that i successfully logged out from my identity provider
and from this moment try to do it again and again, how to tell them
to stop it?
Here is what you have to do.
First of all, when working with federated authentication always use HTTPS! Sometime protocol negotiations will fail just because it is plain HTTP. Sometimes browsers will block non-secure traffic, which is crucial for the sign-out process. So, always use HTTPS!
Now, to implement the form of single sign out you want you have do some more work.
Your URL for sign-out:
mysite.accesscontrol.windows.net/v2/wsfederation?wa=wsignout1.0&wreply=http%3a%2f%2flocalhost%2fAdministration.Frontend.Web%2f&wtrealm=http%3a%2f%2flocalhost%2fAdministration.Frontend.Web%2f
Do not use it as a parameter to construct SignOutRequestMessage. Use it to directly return Redirect(signOutUrl)!
You have to implement sign-out in two major places!
First place is your general logOff action method (given you are using MVC) Something similar to what you already have but with an important change:
FormsAuthentication.SignOut();
var signoutProtocolLocation = "https://[your_acs_namespace].accesscontrol.windows.net:443/v2/wsfederation?wa=wsignout1.0&wtrealm=[realm]&wreply=[reply]";
FederatedAuthentication.WSFederationAuthenticationModule.SignOut(signoutProtocolLocation);
Note that here I use the overload with string paramer` to redirect result to ACS SSO location!
Now that very ACS SSO location will generate the above mentioned HTML page with JS and couple of iframe elements. One of them will be something like:
<iframe src="http://localhost/Administration.Frontend.Web/?wa=wsignoutcleanup1.0" style="visibility: hidden"></iframe>
Now that particular location http://localhost/Administration.Frontend.Web/?wa=wsignoutcleanup1.0 is the second place in your code where you have implement the SSO. This request must not redirect to a login page, but must instead process correctly and return 200 or 301 response (which in turn will return 200!)! For the sake of simplicity I will only paste the code used here:
if(Request.QueryString.AllKeys.Contains("wa")
&& Request.QueryString["wa"].Equals("wsignoutcleanup1.0"))
{
FederatedAuthentication.WSFederationAuthenticationModule.SignOut(true);
return RedirectToAction("Index");
}
It is really important that you only call the SignOut(true) overload with true when it is request for wsignoutcleanup action. And not when you do general log-off of users.
Please try all mentioned changes and let me know if it solves your issue!

Resources