Skip to content
Closed
100 changes: 100 additions & 0 deletions password_security/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3

=================
Password Security
=================

This module allows admin to set company-level password security requirements
and enforces them on the user.

It contains features such as

* Password expiration days
* Password length requirement
* Password minimum number of lowercase letters
* Password minimum number of uppercase letters
* Password minimum number of numbers
* Password minimum number of special characters

Configuration
=============

# Navigate to company you would like to set requirements on
# Click the ``Password Policy`` page
# Set the policies to your liking.

Password complexity requirements will be enforced upon next password change for
any user in that company.


Settings & Defaults
-------------------

These are defined at the company level:

===================== ======= ===================================================
Name Default Description
===================== ======= ===================================================
password_expiration 60 Days until passwords expire
password_length 12 Minimum number of characters in password
password_lower True Require lowercase letter in password
password_upper True Require uppercase letters in password
password_numeric True Require number in password
password_special True Require special character in password
password_history 30 Disallow reuse of this many previous passwords
password_minimum 24 Amount of hours that must pass until another reset
===================== ======= ===================================================

Usage
=====

Configure using above instructions for each company that should have password
security mandates.

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/149/10.0

Known Issues / Roadmap
======================


Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/LasLabs/odoo-base/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us to smash it by providing detailed and welcomed feedback.


Credits
=======

Images
------

* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.

Contributors
------------

* James Foster <jfoster@laslabs.com>
* Dave Lasley <dave@laslabs.com>

Maintainer
----------

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

This module is maintained by the OCA.

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

To contribute to this module, please visit https://odoo-community.org.
5 changes: 5 additions & 0 deletions password_security/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2015 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).

from . import controllers
from . import models
25 changes: 25 additions & 0 deletions password_security/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2015 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
{

'name': 'Password Security',
"summary": "Allow admin to set password security requirements.",
'version': '11.0.1.0.0',
'author': "LasLabs, Odoo Community Association (OCA)",
'category': 'Base',
'depends': [
'auth_crypt',
'auth_signup',
],
"website": "https://laslabs.com",
"license": "LGPL-3",
"data": [
'views/res_company_view.xml',
'security/ir.model.access.csv',
'security/res_users_pass_history.xml',
],
"demo": [
'demo/res_users.xml',
],
'installable': True,
}
4 changes: 4 additions & 0 deletions password_security/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2015 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).

from . import main
93 changes: 93 additions & 0 deletions password_security/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Copyright 2015 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).

import operator

from odoo import http
from odoo.http import request
from odoo.addons.auth_signup.controllers.main import AuthSignupHome
from odoo.addons.web.controllers.main import ensure_db, Session

from ..exceptions import PassError


class PasswordSecuritySession(Session):

@http.route()
def change_password(self, fields):
new_password = operator.itemgetter('new_password')(
dict(map(operator.itemgetter('name', 'value'), fields))
)
user_id = request.env.user
user_id._check_password(new_password)
return super(PasswordSecuritySession, self).change_password(fields)


class PasswordSecurityHome(AuthSignupHome):

def do_signup(self, qcontext):
password = qcontext.get('password')
user_id = request.env.user
user_id._check_password(password)
return super(PasswordSecurityHome, self).do_signup(qcontext)

@http.route()
def web_login(self, *args, **kw):
ensure_db()
response = super(PasswordSecurityHome, self).web_login(*args, **kw)
if not request.httprequest.method == 'POST':
return response
uid = request.session.authenticate(
request.session.db,
request.params['login'],
request.params['password']
)
if not uid:
return response
users_obj = request.env['res.users'].sudo()
user_id = users_obj.browse(request.uid)
if not user_id._password_has_expired():
return response
user_id.action_expire_password()
request.session.logout(keep_db=True)
redirect = user_id.partner_id.signup_url
return http.redirect_with_hash(redirect)

@http.route()
def web_auth_signup(self, *args, **kw):
try:
return super(PasswordSecurityHome, self).web_auth_signup(
*args, **kw
)
except PassError as e:
qcontext = self.get_auth_signup_qcontext()
qcontext['error'] = e.message
return request.render('auth_signup.signup', qcontext)

@http.route()
def web_auth_reset_password(self, *args, **kw):
""" It provides hook to disallow front-facing resets inside of min
Unfortuantely had to reimplement some core logic here because of
nested logic in parent
"""
qcontext = self.get_auth_signup_qcontext()
if (
request.httprequest.method == 'POST' and
qcontext.get('login') and
'error' not in qcontext and
'token' not in qcontext
):
login = qcontext.get('login')
user_ids = request.env.sudo().search(
[('login', '=', login)],
limit=1,
)
if not user_ids:
user_ids = request.env.sudo().search(
[('email', '=', login)],
limit=1,
)
user_ids._validate_pass_reset()
return super(PasswordSecurityHome, self).web_auth_reset_password(
*args, **kw
)
16 changes: 16 additions & 0 deletions password_security/demo/res_users.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
Copyright 2016 LasLabs Inc.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
-->

<odoo>

<record id="base.user_root" model="res.users">
<field name="password_write_date"
eval="datetime.now()"
/>
</record>

</odoo>
11 changes: 11 additions & 0 deletions password_security/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2015 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).

from odoo.exceptions import Warning as UserError


class PassError(UserError):
""" Example: When you try to create an insecure password."""
def __init__(self, msg):
self.message = msg
super(PassError, self).__init__(msg)
Loading