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

openmrs / openmrs-core / 28515008125

01 Jul 2026 11:43AM UTC coverage: 63.785% (+0.1%) from 63.651%
28515008125

push

github

rkorytkowski
Fix @since 2.9.x to 2.9.0

24079 of 37750 relevant lines covered (63.79%)

0.64 hits per line

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

75.0
/api/src/main/java/org/openmrs/aop/AuthorizationAdvice.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.aop;
11

12
import java.lang.reflect.Method;
13
import java.util.Collection;
14

15
import org.apache.commons.lang3.StringUtils;
16
import org.openmrs.User;
17
import org.openmrs.annotation.AuthorizedAnnotationAttributes;
18
import org.openmrs.api.APIAuthenticationException;
19
import org.openmrs.api.context.Context;
20
import org.openmrs.api.context.Daemon;
21
import org.openmrs.util.PrivilegeConstants;
22
import org.slf4j.Logger;
23
import org.slf4j.LoggerFactory;
24
import org.springframework.aop.MethodBeforeAdvice;
25

26
/**
27
 * This class provides the authorization AOP advice performed before every service layer method
28
 * call.
29
 */
30
public class AuthorizationAdvice implements MethodBeforeAdvice {
1✔
31
        
32
        /**
33
         * Logger for this class and subclasses
34
         */
35
        private static final Logger log = LoggerFactory.getLogger(AuthorizationAdvice.class);
1✔
36
        private static final String USER_IS_NOT_AUTHORIZED_TO_ACCESS = "User {} is not authorized to access {}";
37
        
38
        /**
39
         * Allows us to check whether a user is authorized to access a particular method.
40
         * 
41
         * @param method
42
         * @param args
43
         * @param target
44
         * @throws Throwable
45
         * <strong>Should</strong> notify listeners about checked privileges
46
         */
47
        @Override
48
        public void before(Method method, Object[] args, Object target) throws Throwable {
49
                log.debug("Calling authorization advice before {}", method.getName());
1✔
50
                
51
                if (log.isDebugEnabled()) {
1✔
52
                        User user = Context.getAuthenticatedUser();
×
53
                        log.debug("User {}", user);
×
54
                        if (user != null) {
×
55
                                log.debug("has roles {}", user.getAllRoles());
×
56
                        }
57
                }
58
                
59
                if (Daemon.isDaemonThread()) {
1✔
60
                        return;
1✔
61
                }
62
                
63
                AuthorizedAnnotationAttributes attributes = new AuthorizedAnnotationAttributes();
1✔
64
                Collection<String> privileges = attributes.getAttributes(method);
1✔
65
                boolean requireAll = attributes.getRequireAll(method);
1✔
66
                
67
                // Only execute if the "secure" method has authorization attributes
68
                // Iterate through required privileges and return only if the user has
69
                // one of them
70
                if (!privileges.isEmpty()) {
1✔
71
                        try {
72
                                Context.addProxyPrivilege(PrivilegeConstants.GET_ROLES);
1✔
73
                                for (String privilege : privileges) {
1✔
74
                                        // skip null privileges
75
                                        if (privilege == null || privilege.isEmpty()) {
1✔
76
                                                return;
×
77
                                        }
78
                                        boolean hasPrivilege  = Context.hasPrivilege(privilege);
1✔
79
                                        log.debug("User has privilege {}? {}", privilege, hasPrivilege);
1✔
80

81
                                        if (hasPrivilege) {
1✔
82
                                                if (!requireAll) {
1✔
83
                                                        // if not all required, the first one that they have
84
                                                        // causes them to "pass"
85
                                                        return;
1✔
86
                                                }
87
                                        } else {
88
                                                if (requireAll) {
1✔
89
                                                        // if all are required, the first miss causes them
90
                                                        // to "fail"
91
                                                        throwUnauthorized(Context.getAuthenticatedUser(), method, privilege);
×
92
                                                }
93
                                        }
94
                                }
1✔
95
                        } finally {
96
                                Context.removeProxyPrivilege(PrivilegeConstants.GET_ROLES);
1✔
97
                        }
98
                        
99
                        if (!requireAll) {
1✔
100
                                // If there's no match, then we know there are privileges and
101
                                // that the user didn't have any of them. The user is not
102
                                // authorized to access the method
103
                                throwUnauthorized(Context.getAuthenticatedUser(), method, privileges);
×
104
                        }
105
                        
106
                } else if (attributes.hasAuthorizedAnnotation(method) &&
1✔
107
                        !(Context.isAuthenticated() || Context.hasProxyPrivileges())) {
1✔
108
                        throwUnauthorized(Context.getAuthenticatedUser(), method);
×
109
                }
110
        }
1✔
111
        
112
        /**
113
         * Throws an APIAuthorization exception stating why the user failed
114
         * 
115
         * @param user authenticated user
116
         * @param method acting method
117
         * @param attrs Collection of String privilege names that the user must have
118
         */
119
        private void throwUnauthorized(User user, Method method, Collection<String> attrs) {
120
                log.debug(USER_IS_NOT_AUTHORIZED_TO_ACCESS, user, method.getName());
1✔
121
                throw new APIAuthenticationException(Context.getMessageSourceService().getMessage("error.privilegesRequired",
1✔
122
                    new Object[] { StringUtils.join(attrs, ",") }, null));
1✔
123
        }
124
        
125
        /**
126
         * Throws an APIAuthorization exception stating why the user failed
127
         * 
128
         * @param user authenticated user
129
         * @param method acting method
130
         * @param attr privilege names that the user must have
131
         */
132
        private void throwUnauthorized(User user, Method method, String attr) {
133
                log.debug(USER_IS_NOT_AUTHORIZED_TO_ACCESS, user, method.getName());
×
134
                throw new APIAuthenticationException(Context.getMessageSourceService().getMessage("error.privilegesRequired",
×
135
                    new Object[] { attr }, null));
136
        }
137
        
138
        /**
139
         * Throws an APIAuthorization exception stating why the user failed
140
         * 
141
         * @param user authenticated user
142
         * @param method acting method
143
         */
144
        private void throwUnauthorized(User user, Method method) {
145
                log.debug(USER_IS_NOT_AUTHORIZED_TO_ACCESS, user, method.getName());
1✔
146
                throw new APIAuthenticationException(Context.getMessageSourceService().getMessage("error.aunthenticationRequired"));
1✔
147
        }
148
}
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