/** * This Source Code Form is subject to the terms of the Mozilla Public License, * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. * * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS * graphic logo is a trademark of OpenMRS Inc. */ package org.openmrs.module.webservices.rest.web.filter; import java.io.IOException; import java.nio.charset.Charset; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.api.context.Context; import org.openmrs.module.webservices.rest.web.RestConstants; import org.openmrs.module.webservices.rest.web.RestUtil; /** * Filter intended for all /ws/rest calls that allows the user to authenticate via Basic * authentication. (It will not fail on invalid or missing credentials. We count on the API to throw * exceptions if an unauthenticated user tries to do something they are not allowed to do.) <br/> * <br/> * IP address authorization is also performed based on the global property: * {@link RestConstants#ALLOWED_IPS_GLOBAL_PROPERTY_NAME} */ public class AuthorizationFilter implements Filter { protected final Log log = LogFactory.getLog(getClass()); /** * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) */ @Override public void init(FilterConfig arg0) throws ServletException { log.debug("Initializing REST WS Authorization filter"); } /** * @see javax.servlet.Filter#destroy() */ @Override public void destroy() { log.debug("Destroying REST WS Authorization filter"); } /** * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, * javax.servlet.ServletResponse, javax.servlet.FilterChain) */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // check the IP address first. If its not valid, return a 403 if (!RestUtil.isIpAllowed(request.getRemoteAddr())) { // the ip address is not valid, set a 403 http error code HttpServletResponse httpresponse = (HttpServletResponse) response; httpresponse.sendError(HttpServletResponse.SC_FORBIDDEN, "IP address '" + request.getRemoteAddr() + "' is not authorized"); } // skip if the session has timed out, we're already authenticated, or it's not an HTTP request if (request instanceof HttpServletRequest) { HttpServletRequest httpRequest = (HttpServletRequest) request; if (httpRequest.getRequestedSessionId() != null && !httpRequest.isRequestedSessionIdValid()) { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Session timed out"); } if (!Context.isAuthenticated()) { String basicAuth = httpRequest.getHeader("Authorization"); if (basicAuth != null) { // this is "Basic ${base64encode(username + ":" + password)}" try { basicAuth = basicAuth.substring(6); // remove the leading "Basic " String decoded = new String(Base64.decodeBase64(basicAuth), Charset.forName("UTF-8")); String[] userAndPass = decoded.split(":"); Context.authenticate(userAndPass[0], userAndPass[1]); if (log.isDebugEnabled()) log.debug("authenticated " + userAndPass[0]); } catch (Exception ex) { // This filter never stops execution. If the user failed to // authenticate, that will be caught later. } } } } // continue with the filter chain in all circumstances chain.doFilter(request, response); } }