/** * The contents of this file are subject to the OpenMRS Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.aop; import java.lang.reflect.Method; import java.util.Collection; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.User; import org.openmrs.annotation.AuthorizedAnnotationAttributes; import org.openmrs.api.APIAuthenticationException; import org.openmrs.api.context.Context; import org.springframework.aop.MethodBeforeAdvice; /** * This class provides the authorization AOP advice performed before every service layer method * call. */ public class AuthorizationAdvice implements MethodBeforeAdvice { /** * Logger for this class and subclasses */ protected static final Log log = LogFactory.getLog(AuthorizationAdvice.class); /** * Allows us to check whether a user is authorized to access a particular method. * * @param method * @param args * @param target * @throws Throwable */ @SuppressWarnings( { "unchecked" }) public void before(Method method, Object[] args, Object target) throws Throwable { if (log.isDebugEnabled()) log.debug("Calling authorization advice before " + method.getName()); User user = Context.getAuthenticatedUser(); if (log.isDebugEnabled()) { log.debug("User " + user); if (user != null) log.debug("has roles " + user.getAllRoles()); } AuthorizedAnnotationAttributes attributes = new AuthorizedAnnotationAttributes(); Collection<String> attrs = attributes.getAttributes(method); boolean requireAll = attributes.getRequireAll(method); // Only execute if the "secure" method has authorization attributes // Iterate through required privileges and return only if the user has // one of them if (attrs.size() > 0) { for (String privilege : attrs) { // skip null privileges if (privilege == null || privilege.length() < 1) return; if (log.isDebugEnabled()) log.debug("User has privilege " + privilege + "? " + Context.hasPrivilege(privilege)); if (Context.hasPrivilege(privilege)) { if (requireAll == false) { // if not all required, the first one that they have // causes them to "pass" return; } } else if (requireAll == true) { // if all are required, the first miss causes them // to "fail" throwUnauthorized(user, method, privilege); } } if (requireAll == false) { // If there's no match, then we know there are privileges and // that the user didn't have any of them. The user is not // authorized to access the method throwUnauthorized(user, method, attrs); } } else if (attributes.hasAuthorizedAnnotation(method)) { // if there are no privileges defined, just require that // the user be authenticated if (Context.isAuthenticated() == false) throwUnauthorized(user, method); } } /** * Throws an APIAuthorization exception stating why the user failed * * @param user authenticated user * @param method acting method * @param attrs Collection of String privilege names that the user must have */ private void throwUnauthorized(User user, Method method, Collection<String> attrs) { if (log.isDebugEnabled()) log.debug("User " + user + " is not authorized to access " + method.getName()); throw new APIAuthenticationException("Privileges required: " + attrs); } /** * Throws an APIAuthorization exception stating why the user failed * * @param user authenticated user * @param method acting method * @param attrs privilege names that the user must have */ private void throwUnauthorized(User user, Method method, String attr) { if (log.isDebugEnabled()) log.debug("User " + user + " is not authorized to access " + method.getName()); throw new APIAuthenticationException("Privilege required: " + attr); } /** * Throws an APIAuthorization exception stating why the user failed * * @param user authenticated user * @param method acting method */ private void throwUnauthorized(User user, Method method) { if (log.isDebugEnabled()) log.debug("User " + user + " is not authorized to access " + method.getName()); throw new APIAuthenticationException("Basic authentication required"); } }