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
11 changes: 11 additions & 0 deletions spp_drims_sl/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,17 @@ 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. A migration archives them the same way on upgrade
from a released version (the install hook does not run on ``-u``),
closing the system-admin login vector on the upgrade path.

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
27 changes: 27 additions & 0 deletions spp_drims_sl/migrations/19.0.2.0.1/post-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
import logging

from odoo import SUPERUSER_ID, api

_logger = logging.getLogger(__name__)


def migrate(cr, version):
"""Neutralize default-credential demo users on upgrade from a pre-fix release.

The install-time ``post_init_hook`` only runs on a fresh install, not on ``-u``.
A production database that installed a released version of this module before
the fix has the well-known-password demo users active — including
``user_admin_dmc`` which holds ``base.group_system`` — so upgrading would leave
a system-admin login vector open. Re-run the same archiving here so the upgrade
path is covered. Idempotent: on a demo/evaluation database (module.demo True)
it is a no-op, and it only touches users that are still active.
"""
env = api.Environment(cr, SUPERUSER_ID, {})
from odoo.addons.spp_drims_sl import (
DEFAULT_DEMO_USER_XMLIDS,
deactivate_default_demo_users,
demo_data_enabled,
)

deactivate_default_demo_users(env, DEFAULT_DEMO_USER_XMLIDS, demo_data_enabled(env, "spp_drims_sl"))
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. A migration archives them the same way on upgrade from a released version (the install hook does not run on `-u`), closing the system-admin login vector on the upgrade path.

### 19.0.2.0.0

- Initial migration to OpenSPP2
12 changes: 12 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,18 @@ <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. A migration archives them the same way on upgrade
from a released version (the install hook does not run on <tt class="docutils literal"><span class="pre">-u</span></tt>),
closing the system-admin login vector on the upgrade path.</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")
11 changes: 11 additions & 0 deletions spp_drims_sl_demo/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ 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. A migration archives them the same way
on upgrade from a released version (the install hook does not run on
``-u``).

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
24 changes: 24 additions & 0 deletions spp_drims_sl_demo/migrations/19.0.2.0.1/post-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
import logging

from odoo import SUPERUSER_ID, api

_logger = logging.getLogger(__name__)


def migrate(cr, version):
"""Neutralize default-credential demo users on upgrade from a pre-fix release.

The install-time ``post_init_hook`` only runs on a fresh install, not on ``-u``.
A production database that installed a released version of this module before
the fix has the well-known-password demo users active; upgrading would leave
them active. Re-run the same archiving here so the upgrade path is covered.
The archiving helper lives in spp_drims_sl (this module's dependency).
Idempotent: on a demo/evaluation database (module.demo True) it is a no-op,
and it only touches users that are still active.
"""
env = api.Environment(cr, SUPERUSER_ID, {})
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

deactivate_default_demo_users(env, DEFAULT_DEMO_USER_XMLIDS, demo_data_enabled(env, "spp_drims_sl_demo"))
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. A migration archives them the same way on upgrade from a released version (the install hook does not run on `-u`).

### 19.0.2.0.0

- Initial migration to OpenSPP2
12 changes: 12 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,18 @@ <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. A migration archives them the same way
on upgrade from a released version (the install hook does not run on
<tt class="docutils literal"><span class="pre">-u</span></tt>).</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
Loading
Loading