Allauth user_logged_in signal does not trigger in a TestCase - django-allauth

I'm using allauth for user management in my Django web app and I have functionality which finds session data stored when the user was not logged in and stores it when they next log in on the same session.
It is triggered on login via the standard allauth signal:
#receiver(user_logged_in)
def update_on_login(request, user, **kwargs):
print('Signal triggered')
# Do some stuff with session data here, e.g.:
for session_key in request.session.items():
...
This works perfectly when logging in via a web browser, but in TestCase functions the signal is not triggered at all when logging in with:
self.client = Client()
logged_in = self.client.login(username=self.username, password=self.password)
(I've also tried force_login and force_authenticate, but info on these indicates that they actually skip all real validation and just assume the user is logged in).
I think I've understood that client.login doesn't work because the test client doesn't really handle the request in the same way as a web browser would, but I can't say I really understand it.
I've also seen some indication that RequestFactory might be able to help in someway, but I haven't been able to trigger the signal with this either:
request = RequestFactory().post(reverse('account_login'), { 'username': self.username, 'password': self.password })
request.user = AnonymousUser()
response = login(request)
I've seen some comments about needing to call middleware as well, but pretty out of date and nothing clear enough for me to understand and try.
Any suggestions to point me in the right direction would be much appreciated.
Thanks in advance.

Related

End Point API, FastAPI and supabase, sign_in & sign_out user

I'm facing a problem with my backend app, I want to create 3 endpoint API:
/login user
/logout
/getuser
I'm using python FastAPI and supabase, the question is how to create session from my backend app to get connected user information to handle th log_out and the log_in.
log_in function endpoint
#app.post('/login')
async def handel_login(user_mail: str):
if check(user_mail):
print(supabase.auth.sign_in(email=user_mail))
else:
print("incorrect form of email")
log_ou endpoint
#app.get('/logout')
async def handel_logout():
error = supabase.auth.sign_out()
return error
getuser endpoint
#app.get('/getuser')
async def get_user():
user = supabase.auth.user()
return user
in all of this I get None responses!
Supabase-py maintainer here - thanks for the query! FastAPI uses Starlet under the hood so your probably want to make use of the Session Middleware provided by Starlet.
Thereafter, you can do something similar of this format. This is for Django so you may need to make minor tweaks:
try:
data = supabase.auth.sign_in(email="generictestemail123now#gmail.com", password="supersecurepassword")
request.session['user'] = data.json()
except APIError:
pass
Thereafter, you can check if the user is authenticated by reading from the session and validating the JWT.
Hope this helps and please let me know if there are any further issues.
Additional References
[0] - session object in Fastapi similar to flask

Correlation failed when logging in for the second time after hitting the back button on the browser

Ok, first question ever so be gentle. I've been struggling with this for about a week now and i am finally ready to accept defeat and ask for help.
Here's what is happening. I have an IdentityServer4 IDP, an API and an MVC Core Client. I am also interacting with 2 external OAuth2 IDPs provided by the business client.
My problem scenario is this:
The user logs in through my IDP(or potentially one of the external ones)
Once the user is in the Mvc Client they hit the back button on their browser
Which takes them back to the login page(whichever one they used)
They reenter the credentials(login again)
When redirected back(either to the MVC in the case of my IDP, or my IDP in the case of one of the external IDPs) i get RemoteFailure event with the message:correlation failed error
The problem seems, to me, to be the fact that you are trying to login when you are already logged in(or something). I've managed to deal with the case of logging in at my IDP, since the back button step takes the user to my Login action on the Controller(I then check if a user is authenticated and send them back to the MVC without showing them any page) but with the other two IDPs the back button does not hit any code in my IDP. Here are the config options for one of the OAuth2 external IDPs:
.AddOAuth(AppSettings.ExternalProvidersSettings.LoginProviderName, ExternalProviders.LoginLabel, o =>
{
o.ClientId = "clientId";
o.ClientSecret = "clientSecret";
o.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
o.CallbackPath = PathString.FromUriComponent(AppSettings.ExternalProvidersSettings.LoginCallbackPath);
o.AuthorizationEndpoint = AppSettings.ExternalProvidersSettings.LoginAuthorizationEndpoint;
o.TokenEndpoint = AppSettings.ExternalProvidersSettings.LoginTokenEndpoint;
o.Scope.Add("openid");
o.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
//stuff
},
OnRemoteFailure = async context =>
{
if (!HostingEnvironment.IsDevelopment())
{
context.Response.Redirect($"/home/error");
context.HandleResponse();
}
}
};
}
The other one is the same. Since the error is exactly the same regardless of the IDP used, i am guessing it is not something native to OIDC but to OAuth middleware and the code(config options) they share, so i am not going to show the OIDC config on the MVC client(unless you insist). Given how simple the repro steps are i thought i would find an answer and explanation to my problem pretty fast, but i was not able to. Maybe the fix is trivial and i am just blind. Regardless of the situation, i would apreciate help.
I could reproduce your issue.
When the user goes back to the login screen after successfully logging in,
it might well be that the query parameters in the URL of that page are no longer valid.
Don't think this is an issue specific to Identity Server.
You may read
https://github.com/IdentityServer/IdentityServer4/issues/1251
https://github.com/IdentityServer/IdentityServer4/issues/720
Not sure how to prevent this from happening though.

Configure multiple login sessions using google oauth

I am using Google OAuth for Google signin with Odoo.
Everything works fine and I can sign in using google with no problem. However, I cannot open multiple sessions using my same google credentials.
For example, if I open two sessions, one in chrome and another in firefox, then the older session gets logged out.
I don't understand what's the problem because no matter how many sessions I start if I log in using my username and password separately, without using google OAuth, none of the sessions get logged out - works fine.
I was wondering it has got something to do with the code, so I did a lot of tweaks but nothing works. I saw that at one point it cannot get the session information of older sessions. However my question is not about the code.
My question is, is there any configuration or setting to be set in google OAuth or Odoo 8 which lets users have multiple sessions at the same time or is there any setting while using google OAuth with Odoo that I need to know for this?
Any idea would be really helpful as I've been struggling for days with this. Thanks!
I have build a module for Odoo V9. Without this module, Odoo save only one token. But when you use odoo in multi computer, you use one token for each computer.
By default odoo don't support multi token. You need to modify the code of module auth_oauth.
With this module it save all token, like that you can have multi connection.
You can donwload and instal this module : https://github.com/IguanaYachts/auth_oauth_multi_token.git
class ResUsers(models.Model):
_inherit = 'res.users'
oauth_access_token_ids = fields.One2many('auth.oauth.multi.token', 'user_id', 'Tokens', copy=False)
oauth_access_max_token = fields.Integer('Number of simultaneous connections', default=5, required=True)
#api.model
def _auth_oauth_signin(self, provider, validation, params):
res = super(ResUsers, self)._auth_oauth_signin(provider, validation, params)
oauth_uid = validation['user_id']
user_ids = self.search([('oauth_uid', '=', oauth_uid), ('oauth_provider_id', '=', provider)]).ids
if not user_ids:
raise openerp.exceptions.AccessDenied()
assert len(user_ids) == 1
self.oauth_access_token_ids.create({'user_id': user_ids[0],
'oauth_access_token': params['access_token'],
'active_token': True,
})
return res
#api.multi
def clear_token(self):
for users in self:
for token in users.oauth_access_token_ids:
token.write({
'oauth_access_token': "****************************",
'active_token': False})
#api.model
def check_credentials(self, password):
try:
return super(ResUsers, self).check_credentials(password)
except openerp.exceptions.AccessDenied:
res = self.env['auth.oauth.multi.token'].sudo().search([
('user_id', '=', self.env.uid),
('oauth_access_token', '=', password),
('active_token', '=', True),
])
if not res:
raise
If you follow the steps above you will be able to successfully configure Google Apps (Gmail) with OpenERP via the OAuth module. The only thing i was missing is an extra step I found in a youtube video; you have to:
Go to Settings - Users
To the users you want to give OAuth access, send them a password reset by using the "Send reset password instructions by email" option.
Ask your users (or yourself) to use the link they receive in their email, but, when they open it, they will only see the log in screen with the "Log in with Google" option. (no typical change password option available)
Use the proper Google account and voila! - Now it connects smoothly.
The Youtube video that show how to log in with Google in OpenERP: http://www.youtube.com/watch?v=A-iwzxEeJmc
and if configuration of Oauth2 and odoo see this link for more detail
https://odootricks.wordpress.com/2014/09/18/setting-up-google-apps-authentication-for-odoo/

CI 2.0.3 session heisenbug: session is lost after some time 20 minutes, only on server redirect, nothing suspicious in the logs

I can't seem to make any progress with this one. My CI session settings are these:
$config['sess_cookie_name'] = 'ci_session';
$config['sess_expiration'] = 0;
$config['sess_expire_on_close'] = FALSE;
$config['sess_encrypt_cookie'] = FALSE;
$config['sess_use_database'] = TRUE;
$config['sess_table_name'] = 'ci_sessions';
$config['sess_match_ip'] = FALSE;
$config['sess_match_useragent'] = FALSE;
$config['sess_time_to_update'] = 7200;
$config['cookie_prefix'] = "";
$config['cookie_domain'] = "";
$config['cookie_path'] = "/";
$config['cookie_secure'] = FALSE;
The session library is loaded on autoload. I've commented the sess_update function to prevent an AJAX bug that I've found about reading the CI forum.
The ci_sessions table in the database has collation utf8_general_ci (there was a bug that lost the session after every redirect() call and it was linked to the fact that the collation was latin1_swedish_ci by default).
It always breaks after a user of my admin section tries to add a long article and clicks the save button. The save action looks like this:
function save($id = 0){
if($this->my_model->save_article($id)){
$this->session->set_flashdata('message', 'success!');
redirect('admin/article_listing');
}else{
$this->session->set_flashdata('message', 'errors encountered');
redirect('admin/article_add');
}
}
If you spend more than 20minutes and click save, the article will be added but on redirect the user will be logged out.
I've also enabled logging and sometimes when the error occurs i get the message The session cookie data did not match what was expected. This could be a possible hacking attempt. but only half of the time. The other half I get nothing: a message that I've placed at the end of the Session constructor is displayed and nothing else. In all the cases if I look at the cookie stored in my browser, after the error the cookie's first part doesn't match the hash.
Also, although I know Codeigniter doesn't use native sessions, I've set session.gc_maxlifetime to 86400.
Another thing to mention is that I'm unable to reproduce the error on my computer but on all the other computers I've tested this bug appears by the same pattern as mentioned above.
If you have any ideas on what to do next, I'd greatly appreciate them. Changing to a new version or using a native session class (the old one was for CI 1.7, will it still work?) are also options I'm willing to consider.
Edit : I've run a diff between the Session class in CI 2.0.3 and the latest CI Session class and they're the same.
Here's how I solved it: the standards say that a browser shouldn't allow redirects after a POST request. CI's redirect() method is sending a 302 redirect by default. The logical way would be to send a 307 redirect, which solved my problem but has the caveat of showing a confirm dialog about the redirect. Other options are a 301 (meaning moved permanently) redirect or, the solution I've chosen, a javascript redirect.

Google Federated OAuth/OpenID with Tornado: why is it ignoring my scopes?

I'm trying to use Tornado's library for federated login to authenticate users and get access to their calendar, contacts, and mail. However, when I get the "mydomain.dyndns.info is asking for some information from your Google Account" message, the only bullet point listed is "Email Address". Subsequently, when I check the returned user object after I approve the request, the user object doesn't have an 'access_token' property.
Here's the code:
def get(self):
scope_list = ['https://mail.google.com/','http://www.google.com/m8/feeds/','http://www.google.com/calendar/feeds/']
...
self.authorize_redirect(scope_list, callback_uri=self._switch_command('auth_callback'), ax_attrs=["name","email"])
def _on_auth(self, user):
print 'in on auth'
if user:
self.set_the_user(user['email'])
session.set_data('usertoken_' + user['email'], user['access_token'])
self.redirect('/')
The uri that this spits out is:
https://www.google.com/accounts/o8/ud
?openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0
&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select
&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select
&openid.return_to=http%3A%2F%2Fmydomain.dyndns.info%3A333%2Fauth%2Fauth_callback%3Fperms%3Dgmail%26perms%3Dcontacts%26perms%3Dcalendar
&openid.realm=http%3A%2F%2Fmydomain.dyndns.info%3A333%2F
&openid.mode=checkid_setup
&openid.ns.oauth=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Foauth%2F1.0
&openid.oauth.consumer=mydomain.dyndns.info
&openid.oauth.scope=https%3A%2F%2Fmail.google.com%2F+http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds%2F+http%3A%2F%2Fwww.google.com%2Fcalendar%2Ffeeds%2F
&openid.ns.ax=http%3A%2F%2Fopenid.net%2Fsrv%2Fax%2F1.0
&openid.ax.type.fullname=http%3A%2F%2Faxschema.org%2FnamePerson
&openid.ax.type.lastname=http%3A%2F%2Faxschema.org%2FnamePerson%2Flast
&openid.ax.type.firstname=http%3A%2F%2Faxschema.org%2FnamePerson%2Ffirst
&openid.ax.mode=fetch_request
&openid.ax.type.email=http%3A%2F%2Faxschema.org%2Fcontact%2Femail
&openid.ax.required=firstname%2Cfullname%2Clastname%2Cemail
Ideas: 1. maybe this has something to do with the fact I'm running on a local machine behind a dyndns forwarder? 2. Tornado's documentation says "No application registration is necessary to use Google for authentication or to access Google resources on behalf of a user" -- but maybe that's not true anymore?
If anyone has thoughts, I'd really appreciate it -- this is driving me a little batty!
Figured it out. You have to set the application properties google_consumer_key and google_consumer_secret.
application = tornado.web.Application(urlhandlers, cookie_secret=cookie_secret, google_consumer_key=google_consumer_key, google_consumer_secret=google_consumer_secret)
You get them by going here: https://www.google.com/accounts/ManageDomains

Resources