• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmrs / openmrs-core / 27768587422

18 Jun 2026 02:59PM UTC coverage: 63.728% (+0.05%) from 63.675%
27768587422

push

github

web-flow
Require Get Alerts privilege to read all users' alerts (#6206)

Backport of #6186 to 2.9.x.

AlertService.getAllAlerts() and getAllAlerts(boolean) return every user's
alerts but were guarded only by @Authorized (authentication), so any
authenticated user could read alerts addressed to others. Introduce a
dedicated Get Alerts privilege (GET_* read-privilege convention) and gate both
methods with it. The per-user reads (getAlert, getAlerts, getAlertsByUser,
getAllActiveAlerts) stay open for a caller reading their own alerts; reading
another user's alerts through them now requires Get Alerts. getAlert(Integer)
returns null (rather than throwing) for another user's alert, the same as for
an unknown id, so it cannot be used as an existence oracle.

The privilege is created on startup via @AddOnStartup / checkCoreDataset() and
is not auto-granted to any role, so it does not reintroduce the leak. The
scheduled AlertReminderTask grants itself a proxy Get Alerts privilege around
its read of all alerts.


Claude-Session: https://claude.ai/code/session_01GswaapaA8WAbd7V7dv3yxW

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

10 of 13 new or added lines in 2 files covered. (76.92%)

4 existing lines in 2 files now uncovered.

23940 of 37566 relevant lines covered (63.73%)

0.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/api/src/main/java/org/openmrs/scheduler/tasks/AlertReminderTask.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs.scheduler.tasks;
11

12
import java.util.Collection;
13
import java.util.HashSet;
14

15
import org.openmrs.User;
16
import org.openmrs.api.context.Context;
17
import org.openmrs.notification.Alert;
18
import org.openmrs.notification.AlertRecipient;
19
import org.openmrs.notification.Message;
20
import org.openmrs.notification.MessageException;
21
import org.openmrs.util.PrivilegeConstants;
22
import org.slf4j.Logger;
23
import org.slf4j.LoggerFactory;
24

25
/**
26
 * Sample implementation of task that shows how to send emails to users/roles via message service.
27
 */
28
public class AlertReminderTask extends AbstractTask {
×
29
        
30
        // Logger 
31
        private static final Logger log = LoggerFactory.getLogger(AlertReminderTask.class);
×
32
        
33
        /**
34
         * Send alert reminder email to user(s) associated with the alert.
35
         */
36
        @Override
37
        public void execute() {
38
                try {
39
                        // Get all unread alerts
40
                        // TODO Change to getAllAlerts(Boolean includeRead, Boolean includeExpired);
41
                        // getAllAlerts requires the Get Alerts privilege; this system task reads every
42
                        // user's alerts to notify them, so grant the privilege for the duration of the read.
43
                        Collection<Alert> alerts;
NEW
44
                        Context.addProxyPrivilege(PrivilegeConstants.GET_ALERTS);
×
45
                        try {
NEW
46
                                alerts = Context.getAlertService().getAllAlerts(false);
×
47
                        } finally {
NEW
48
                                Context.removeProxyPrivilege(PrivilegeConstants.GET_ALERTS);
×
49
                        }
50

51
                        // Send alert notifications to users who have unread alerts
52
                        sendAlertNotifications(alerts);
×
53
                        
54
                }
55
                catch (Exception e) {
×
56
                        log.error("Failed to send alert notifications", e);
×
57
                }
×
58
        }
×
59
        
60
        /**
61
         * Send alerts
62
         * 
63
         * @param alerts the unread alerts
64
         */
65
        private void sendAlertNotifications(Collection<Alert> alerts) {
66
                
67
                try {
68
                        
69
                        // Create a new message
70
                        Message message = Context.getMessageService().createMessage("Alert Reminder", "You have unread alerts.");
×
71
                        
72
                        // Get all recipients
73
                        Collection<User> users = getRecipients(alerts);
×
74
                        
75
                        // Send a message to each person only once
76
                        Context.getMessageService().sendMessage(message, users);
×
77
                        
78
                }
79
                catch (MessageException e) {
×
80
                        log.error("Failed to send message", e);
×
81
                }
×
82
        }
×
83
        
84
        /**
85
         * Get the recipients of all unread alerts.
86
         * 
87
         * @param alerts
88
         * @return the users who have not read the alerts
89
         */
90
        private Collection<User> getRecipients(Collection<Alert> alerts) {
91
                Collection<User> users = new HashSet<>();
×
92
                for (Alert alert : alerts) {
×
93
                        log.debug("Send email to alert recipient(s) ...");
×
94
                        if (!alert.isAlertRead() && alert.getRecipients() != null) {
×
95
                                for (AlertRecipient recipient : alert.getRecipients()) {
×
96
                                        if (!recipient.isAlertRead() && recipient.getRecipient() != null) {
×
97
                                                users.add(recipient.getRecipient());
×
98
                                        }
99
                                }
×
100
                        }
101
                }
×
102
                return users;
×
103
        }
104
        
105
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc