Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions spp_drims_sl/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,15 @@ Dependencies
Changelog
=========

19.0.2.0.1
~~~~~~~~~~

- fix(security): archive the 14 default-credential DRIMS-SL demo users
(shared password ``demo``, including ``admin.dmc@drims.gov.lk`` which
holds ``base.group_system``) on a production install via a
self-contained ``post_init_hook``; they stay active only when demo
data is enabled.

19.0.2.0.0
~~~~~~~~~~

Expand Down
65 changes: 64 additions & 1 deletion spp_drims_sl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,65 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
# Configuration module - no Python imports
import logging

_logger = logging.getLogger(__name__)

# res.users records created with the shared, documented password "demo" by
# data/demo_users.xml (including "user_admin_dmc", which holds base.group_system).
# They load via the `data` section, so they exist after any install — including a
# production database installed without demo data, where the well-known
# credentials would be a login vector. This module does not depend on spp_demo,
# so the archiving helper is kept self-contained here.
DEFAULT_DEMO_USER_XMLIDS = [
"spp_drims_sl.user_admin_dmc",
"spp_drims_sl.user_wh_staff_colombo",
"spp_drims_sl.user_wh_staff_kandy",
"spp_drims_sl.user_wh_colombo",
"spp_drims_sl.user_wh_kandy",
"spp_drims_sl.user_approver_national",
"spp_drims_sl.user_approver_western",
"spp_drims_sl.user_approver_central",
"spp_drims_sl.user_officer_colombo",
"spp_drims_sl.user_officer_gampaha",
"spp_drims_sl.user_officer_kandy",
"spp_drims_sl.user_officer_galle",
"spp_drims_sl.user_viewer_secretary",
"spp_drims_sl.user_viewer_director",
]


def demo_data_enabled(env, module_name):
"""Return True if demo data was loaded for ``module_name`` on this database."""
module = env["ir.module.module"].search([("name", "=", module_name)], limit=1)
return bool(module.demo)


def deactivate_default_demo_users(env, xmlids, demo_enabled):
"""Deactivate default-credential demo users unless demo data is enabled.

On a database with demo data (an evaluation/demo instance) the accounts are
left active so demos work. On a database WITHOUT demo data (a
production-style install) they are archived so the well-known ``demo``
password cannot be used to log in. Returns the users that were deactivated.
"""
if demo_enabled:
return env["res.users"].browse()
users = env["res.users"].browse()
for xmlid in xmlids:
user = env.ref(xmlid, raise_if_not_found=False)
if user and user.active:
users |= user
if users:
users.active = False
_logger.warning(
"Demo data is disabled; archived %d default-credential DRIMS-SL demo "
"user(s): %s. Re-activate them deliberately only on a "
"non-production instance.",
len(users),
", ".join(users.mapped("login")),
)
return users


def post_init_hook(env):
"""Neutralize the default-credential demo users on a production install."""
deactivate_default_demo_users(env, DEFAULT_DEMO_USER_XMLIDS, demo_data_enabled(env, "spp_drims_sl"))
3 changes: 2 additions & 1 deletion spp_drims_sl/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"inventory management. Includes geographic hierarchy, government agencies, "
"and approval thresholds per DMC requirements.",
"category": "OpenSPP/Inventory",
"version": "19.0.2.0.0",
"version": "19.0.2.0.1",
"sequence": 1,
"author": "OpenSPP.org",
"website": "https://github.com/OpenSPP/OpenSPP2",
Expand Down Expand Up @@ -39,6 +39,7 @@
# Second pass: enable multitier (must load after tiers are created)
"data/approval_config_multitier.xml",
],
"post_init_hook": "post_init_hook",
"application": False,
"installable": True,
"auto_install": False,
Expand Down
6 changes: 6 additions & 0 deletions spp_drims_sl/data/demo_users.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
- officer.galle@drims.gov.lk - Field Officer
- secretary@drims.gov.lk - Secretary (Viewer, for dashboard tutorial)
- director@drims.gov.lk - Director (Viewer)

SECURITY: these users share the well-known password "demo" and load via the
manifest `data` section, so they exist after any install. On a production
database (installed without demo data) they are archived by this module's
post_init_hook (see __init__.py) so the well-known password cannot be used
to log in; on a demo/evaluation database they stay active.
-->

<!-- ==================== SUPER ADMIN ==================== -->
Expand Down
4 changes: 4 additions & 0 deletions spp_drims_sl/readme/HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### 19.0.2.0.1

- fix(security): archive the 14 default-credential DRIMS-SL demo users (shared password `demo`, including `admin.dmc@drims.gov.lk` which holds `base.group_system`) on a production install via a self-contained `post_init_hook`; they stay active only when demo data is enabled.

### 19.0.2.0.0

- Initial migration to OpenSPP2
10 changes: 10 additions & 0 deletions spp_drims_sl/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,16 @@ <h2><a class="toc-backref" href="#toc-entry-1">Changelog</a></h2>
</div>
</div>
<div class="section" id="section-1">
<h1>19.0.2.0.1</h1>
<ul class="simple">
<li>fix(security): archive the 14 default-credential DRIMS-SL demo users
(shared password <tt class="docutils literal">demo</tt>, including <tt class="docutils literal">admin.dmc&#64;drims.gov.lk</tt> which
holds <tt class="docutils literal">base.group_system</tt>) on a production install via a
self-contained <tt class="docutils literal">post_init_hook</tt>; they stay active only when demo
data is enabled.</li>
</ul>
</div>
<div class="section" id="section-2">
<h1>19.0.2.0.0</h1>
<ul class="simple">
<li>Initial migration to OpenSPP2</li>
Expand Down
1 change: 1 addition & 0 deletions spp_drims_sl/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
from . import test_spp_drims_sl
from . import test_demo_user_safety
83 changes: 83 additions & 0 deletions spp_drims_sl/tests/test_demo_user_safety.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
"""Safety tests for this module's default-credential demo users.

``data/demo_users.xml`` creates DRIMS Sri Lanka users with the shared password
``demo`` (including ``user_admin_dmc``, which holds ``base.group_system``). On a
production database (installed without demo data) they must be deactivated; on a
demo/evaluation database they must stay active. This module does not depend on
spp_demo, so the archiving helper is self-contained here.
"""

from odoo.modules.module import get_manifest
from odoo.tests import TransactionCase, tagged

from odoo.addons.spp_drims_sl import (
DEFAULT_DEMO_USER_XMLIDS,
deactivate_default_demo_users,
demo_data_enabled,
post_init_hook,
)


@tagged("post_install", "-at_install")
class TestDrimsSlDemoUserSafety(TransactionCase):
def _default_users(self):
users = self.env["res.users"].browse()
for xmlid in DEFAULT_DEMO_USER_XMLIDS:
user = self.env.ref(xmlid, raise_if_not_found=False)
if user:
users |= user
return users

def test_default_users_deactivated_when_demo_disabled(self):
users = self._default_users()
self.assertTrue(users, "DRIMS-SL demo users should exist in the test database")
users.active = True

deactivated = deactivate_default_demo_users(self.env, DEFAULT_DEMO_USER_XMLIDS, demo_enabled=False)

self.assertEqual(set(deactivated.ids), set(users.ids))
self.assertFalse(
any(users.mapped("active")),
"all DRIMS-SL default-credential demo users must be inactive when demo is disabled",
)

def test_admin_user_is_covered(self):
"""The base.group_system super-admin demo account must be in the archive set."""
self.assertIn("spp_drims_sl.user_admin_dmc", DEFAULT_DEMO_USER_XMLIDS)
admin = self.env.ref("spp_drims_sl.user_admin_dmc", raise_if_not_found=False)
self.assertTrue(admin, "user_admin_dmc should exist")
self.assertTrue(admin.has_group("base.group_system"))

def test_default_users_active_when_demo_enabled(self):
users = self._default_users()
users.active = True

deactivate_default_demo_users(self.env, DEFAULT_DEMO_USER_XMLIDS, demo_enabled=True)

self.assertTrue(
all(users.mapped("active")),
"DRIMS-SL demo users must remain active when demo data is enabled",
)

def test_post_init_hook_archives_users_on_production(self):
users = self._default_users()
users.active = True
module = self.env["ir.module.module"].search([("name", "=", "spp_drims_sl")], limit=1)

if module.demo:
self.skipTest("demo data enabled on this database; production path not exercised")

post_init_hook(self.env)

self.assertFalse(
any(users.mapped("active")),
"post_init_hook must archive default-credential users when demo is disabled",
)

def test_demo_data_enabled_matches_module_flag(self):
module = self.env["ir.module.module"].search([("name", "=", "spp_drims_sl")], limit=1)
self.assertEqual(demo_data_enabled(self.env, "spp_drims_sl"), bool(module.demo))

def test_manifest_wires_post_init_hook(self):
self.assertEqual(get_manifest("spp_drims_sl").get("post_init_hook"), "post_init_hook")
9 changes: 9 additions & 0 deletions spp_drims_sl_demo/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,15 @@ Dependencies
Changelog
=========

19.0.2.0.1
~~~~~~~~~~

- fix(security): archive the six default-credential DRIMS-SL demo users
(``kumari``, ``rajitha``, ``silva``, ``perera``, ``fernando``,
``secretary``, shared password ``demo``) on a production install via a
``post_init_hook`` reusing spp_drims_sl's helper; they stay active
only when demo data is enabled.

19.0.2.0.0
~~~~~~~~~~

Expand Down
21 changes: 21 additions & 0 deletions spp_drims_sl_demo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
from . import models
from . import wizard

# res.users records created with the shared, documented password "demo" by
# data/demo_users.xml. They load via the `data` section, so they exist after
# any install — including a production database installed without demo data,
# where the well-known credentials would be a login vector. This module depends
# on spp_drims_sl, so it reuses that module's self-contained archiving helper.
DEFAULT_DEMO_USER_XMLIDS = [
"spp_drims_sl_demo.user_kumari",
"spp_drims_sl_demo.user_rajitha",
"spp_drims_sl_demo.user_silva",
"spp_drims_sl_demo.user_perera",
"spp_drims_sl_demo.user_fernando",
"spp_drims_sl_demo.user_secretary",
]


def post_init_hook(env):
"""Neutralize this module's default-credential demo users in production."""
from odoo.addons.spp_drims_sl import deactivate_default_demo_users, demo_data_enabled

deactivate_default_demo_users(env, DEFAULT_DEMO_USER_XMLIDS, demo_data_enabled(env, "spp_drims_sl_demo"))
3 changes: 2 additions & 1 deletion spp_drims_sl_demo/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"summary": "Demo data generator for DRIMS Sri Lanka implementation. "
"Creates sample incidents, donations, requests, and stock for demonstrations.",
"category": "OpenSPP/Inventory",
"version": "19.0.2.0.0",
"version": "19.0.2.0.1",
"sequence": 1,
"author": "OpenSPP.org",
"website": "https://github.com/OpenSPP/OpenSPP2",
Expand All @@ -24,6 +24,7 @@
"data/demo_gis_reports.xml",
"wizard/demo_generator_views.xml",
],
"post_init_hook": "post_init_hook",
"application": False,
"installable": True,
"auto_install": False,
Expand Down
7 changes: 7 additions & 0 deletions spp_drims_sl_demo/data/demo_users.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
- secretary: Viewer - dashboard and reports only

Login credentials: username / demo

SECURITY: these users share the well-known password "demo" and load via the
manifest `data` section, so they exist after any install. On a production
database (installed without demo data) they are archived by this module's
post_init_hook (see __init__.py, reusing spp_drims_sl's helper) so the
well-known password cannot be used to log in; on a demo/evaluation database
they stay active.
==========================================================================
-->

Expand Down
4 changes: 4 additions & 0 deletions spp_drims_sl_demo/readme/HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### 19.0.2.0.1

- fix(security): archive the six default-credential DRIMS-SL demo users (`kumari`, `rajitha`, `silva`, `perera`, `fernando`, `secretary`, shared password `demo`) on a production install via a `post_init_hook` reusing spp_drims_sl's helper; they stay active only when demo data is enabled.

### 19.0.2.0.0

- Initial migration to OpenSPP2
10 changes: 10 additions & 0 deletions spp_drims_sl_demo/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,16 @@ <h2><a class="toc-backref" href="#toc-entry-1">Changelog</a></h2>
</div>
</div>
<div class="section" id="section-1">
<h1>19.0.2.0.1</h1>
<ul class="simple">
<li>fix(security): archive the six default-credential DRIMS-SL demo users
(<tt class="docutils literal">kumari</tt>, <tt class="docutils literal">rajitha</tt>, <tt class="docutils literal">silva</tt>, <tt class="docutils literal">perera</tt>, <tt class="docutils literal">fernando</tt>,
<tt class="docutils literal">secretary</tt>, shared password <tt class="docutils literal">demo</tt>) on a production install via a
<tt class="docutils literal">post_init_hook</tt> reusing spp_drims_sl’s helper; they stay active
only when demo data is enabled.</li>
</ul>
</div>
<div class="section" id="section-2">
<h1>19.0.2.0.0</h1>
<ul class="simple">
<li>Initial migration to OpenSPP2</li>
Expand Down
1 change: 1 addition & 0 deletions spp_drims_sl_demo/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
from . import test_demo_generator
from . import test_demo_user_safety
71 changes: 71 additions & 0 deletions spp_drims_sl_demo/tests/test_demo_user_safety.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
"""Safety tests for this module's default-credential demo users.

``data/demo_users.xml`` creates DRIMS Sri Lanka demo users with the shared
password ``demo``. On a production database (installed without demo data) they
must be deactivated; on a demo/evaluation database they must stay active. The
archiving helper is reused from spp_drims_sl (this module's dependency).
"""

from odoo.modules.module import get_manifest
from odoo.tests import TransactionCase, tagged

from odoo.addons.spp_drims_sl import deactivate_default_demo_users, demo_data_enabled
from odoo.addons.spp_drims_sl_demo import DEFAULT_DEMO_USER_XMLIDS, post_init_hook


@tagged("post_install", "-at_install")
class TestDrimsSlDemoDemoUserSafety(TransactionCase):
def _default_users(self):
users = self.env["res.users"].browse()
for xmlid in DEFAULT_DEMO_USER_XMLIDS:
user = self.env.ref(xmlid, raise_if_not_found=False)
if user:
users |= user
return users

def test_default_users_deactivated_when_demo_disabled(self):
users = self._default_users()
self.assertTrue(users, "DRIMS-SL demo users should exist in the test database")
users.active = True

deactivated = deactivate_default_demo_users(self.env, DEFAULT_DEMO_USER_XMLIDS, demo_enabled=False)

self.assertEqual(set(deactivated.ids), set(users.ids))
self.assertFalse(
any(users.mapped("active")),
"all DRIMS-SL demo default-credential users must be inactive when demo is disabled",
)

def test_default_users_active_when_demo_enabled(self):
users = self._default_users()
users.active = True

deactivate_default_demo_users(self.env, DEFAULT_DEMO_USER_XMLIDS, demo_enabled=True)

self.assertTrue(
all(users.mapped("active")),
"DRIMS-SL demo users must remain active when demo data is enabled",
)

def test_post_init_hook_archives_users_on_production(self):
users = self._default_users()
users.active = True
module = self.env["ir.module.module"].search([("name", "=", "spp_drims_sl_demo")], limit=1)

if module.demo:
self.skipTest("demo data enabled on this database; production path not exercised")

post_init_hook(self.env)

self.assertFalse(
any(users.mapped("active")),
"post_init_hook must archive default-credential users when demo is disabled",
)

def test_demo_data_enabled_matches_module_flag(self):
module = self.env["ir.module.module"].search([("name", "=", "spp_drims_sl_demo")], limit=1)
self.assertEqual(demo_data_enabled(self.env, "spp_drims_sl_demo"), bool(module.demo))

def test_manifest_wires_post_init_hook(self):
self.assertEqual(get_manifest("spp_drims_sl_demo").get("post_init_hook"), "post_init_hook")
Loading
Loading