How to Handle Suspicious Login in Odoo 15

How to Handle Suspicious Login in Odoo 15

3 minutes, 40 seconds Read

Suspicious login is when a user tries to login apart from their login pattern like from a different device than unusual. So to prevent another person from accessing we may need to track this unusual activity and alert the user about this activity. So that the user can verify it’s them and continue with the login. To implement this in Odoo, we could use the browser’s cookie where we can store the unique key for the user.
Model:
First create a model to save the unique code of the user
from odoo import fields, models
class UsersActivity(models.Model):
   _name = 'res.users.activity'
   _description = User Activity
   user_id = fields.Many2one('res.users', 'User')
   name = fields.Char(related=user_id.name)
   user_uid = fields.Char('User UID')
Here we can save the unique code in the user_uid field and the corresponding user in the user_id field.
We are going to send an OTP if a suspicious login attempt is detected so that the user can verify and continue. To save the OTP we can inherit the user model and create a new field there.
class Users(models.Model):
   _inherit = 'res.users'
   otp = fields.Char('Otp')
View:
We need to create a template for typing the OTP. So that they can verify and log in through another device or browser.
<template id="otp_template">
   <t t-call="web.login_layout">
       <form action="/web/login" method="post" onsubmit="this.action = '/web/login' + location.hash">
           <input name="csrf_token" type="hidden" t-att-value="request.csrf_token()"/>
           <input type="hidden" name="login" t-att-value="login"/>
           <input type="hidden" name="password" t-att-value="password"/>
           <t t-if="error">
               <p class="error"><span t-esc="error"/></p>
           </t>
           <div class="form-group field-otp">
               <input type="password" maxlength="6" class="form-control " id="otp" placeholder="OTP" name="otp" required=""/>
           </div>
           <div class="form-group">
               <input type="checkbox" name="is_trusted"/>
               <label for="is_trusted">Trust this browser?</label>
           </div>
           <button type="submit" class="btn btn-primary">Verify</button>
       </form>
   </t>
</template>
Controller:
We need to extend the web login controller and save the user’s unique code to the browser cookie on the first login or when they verify it’s them.
@http.route()
def web_login(self, redirect=None, **kw):
   response = super(Suspicious, self).web_login(redirect, **kw)
   if request.params.get('login_success'):
       user = request.env.user
       cookies = request.httprequest.cookies # getting the cookies
       activities = request.env['res.users.activity'].search([
           ('user_id', '=', user.id)
       ]) # activity of the current user
       if kw.get('otp'): checking otp present in the kw
           if kw.get('otp') == request.env.user.otp: # comparing the otp
               if kw.get('is_trusted'): # user can check the browser as trusted if they want to login frequently and save the unique id in the browser cookie
                   response.set_cookie('uuid', activities.user_uid, max_age=expire_time)
               return response
           else:
               values = kw
               if kw.get('otp') != request.env.user.otp:
                   message = 'Invalid Otp'
                   values.update({'error': message})
               return request.render('suspicious_login.otp_template', values)
       if activities: # checking if the user have an existing activity
           if activities.user_uid == cookies.get('uuid'): #checking activity user_uid equal to the cookie in the browser
               return response
           else: 
               otp = request.env.user.otp = generate_otp() # generate otp
               # Send a mail to user about Suspicious login and otp
               return request.render('suspicious_login.otp_template', kw)
       else: # First login
           uuid = generate_user_uid() # a function to generate user unique id
           activities.create({
               'user_id': user.id,
               'user_uid': uuid
           }) # creating an user activity with unique id
           response.set_cookie('uuid', uuid, max_age=expire_time) # saving the unique id in the user browser cookie
           return response
   else:
       return response
Here we get the cookie and try to match the cookie uuid and the respected user uuid. If they match, the user gets logged in. If it is wrong the system will send an OTP to the user mail and the user will be redirected to a page where the user can type the OTP. After successfully submitting the OTP user will be logged in. If the OTP is wrong then a new OTP will be sent to the user via mail.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *