/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package org.codice.ddf.security.filter.authorization; import java.io.IOException; 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.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.codice.ddf.security.policy.context.ContextPolicy; import org.codice.ddf.security.policy.context.ContextPolicyManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ddf.security.common.audit.SecurityLogger; import ddf.security.permission.CollectionPermission; /** * Handler that implements authorization checking for contexts. */ public class AuthorizationFilter implements Filter { private static final Logger LOGGER = LoggerFactory.getLogger(AuthorizationFilter.class); private final ContextPolicyManager contextPolicyManager; /** * Default constructor * * @param contextPolicyManager */ public AuthorizationFilter(ContextPolicyManager contextPolicyManager) { super(); this.contextPolicyManager = contextPolicyManager; } @Override public void init(FilterConfig filterConfig) throws ServletException { LOGGER.debug("Starting AuthZ filter."); } @SuppressWarnings("PackageAccessibility") @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; Subject subject = null; if (request.getAttribute(ContextPolicy.NO_AUTH_POLICY) != null) { LOGGER.debug("NO_AUTH_POLICY header was found, skipping authorization filter."); chain.doFilter(request, response); } else { try { subject = SecurityUtils.getSubject(); } catch (Exception e) { LOGGER.debug("Unable to retrieve user from request.", e); } boolean permitted = true; final String path = httpRequest.getRequestURI(); ContextPolicy policy = contextPolicyManager.getContextPolicy(path); if (policy != null && subject != null) { CollectionPermission permissions = policy.getAllowedAttributePermissions(); if (!permissions.isEmpty()) { permitted = subject.isPermitted(permissions); } } else { LOGGER.warn( "Unable to determine policy for path {}. User is not permitted to continue. Check policy configuration!", path); permitted = false; } if (!permitted) { SecurityLogger.audit("Subject not authorized to view resource {}", path); LOGGER.debug("Subject not authorized."); returnNotAuthorized(httpResponse); } else { LOGGER.debug("Subject is authorized!"); chain.doFilter(request, response); } } } /** * Sets status and error codes to forbidden and returns response. * * @param response */ private void returnNotAuthorized(HttpServletResponse response) { try { response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.sendError(HttpServletResponse.SC_FORBIDDEN); response.flushBuffer(); } catch (IOException ioe) { LOGGER.debug("Failed to send auth response: {}", ioe); } } @Override public void destroy() { LOGGER.debug("Destroying AuthZ filter."); } }