001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.shiro.web.filter.authz; 020 021import org.apache.shiro.subject.Subject; 022import org.apache.shiro.util.StringUtils; 023import org.apache.shiro.web.filter.AccessControlFilter; 024import org.apache.shiro.web.util.WebUtils; 025 026import javax.servlet.ServletRequest; 027import javax.servlet.ServletResponse; 028import javax.servlet.http.HttpServletResponse; 029import java.io.IOException; 030 031/** 032 * Superclass for authorization-related filters. If an request is unauthorized, response handling is delegated to the 033 * {@link #onAccessDenied(javax.servlet.ServletRequest, javax.servlet.ServletResponse) onAccessDenied} method, which 034 * provides reasonable handling for most applications. 035 * 036 * @see #onAccessDenied(javax.servlet.ServletRequest, javax.servlet.ServletResponse) 037 * @since 0.9 038 */ 039public abstract class AuthorizationFilter extends AccessControlFilter { 040 041 /** 042 * The URL to which users should be redirected if they are denied access to an underlying path or resource, 043 * {@code null} by default which will issue a raw {@link HttpServletResponse#SC_UNAUTHORIZED} response 044 * (401 Unauthorized). 045 */ 046 private String unauthorizedUrl; 047 048 /** 049 * Returns the URL to which users should be redirected if they are denied access to an underlying path or resource, 050 * or {@code null} if a raw {@link HttpServletResponse#SC_UNAUTHORIZED} response should be issued (401 Unauthorized). 051 * <p/> 052 * The default is {@code null}, ensuring default web server behavior. Override this default by calling the 053 * {@link #setUnauthorizedUrl(String) setUnauthorizedUrl} method with a meaningful path within your application 054 * if you would like to show the user a 'nice' page in the event of unauthorized access. 055 * 056 * @return the URL to which users should be redirected if they are denied access to an underlying path or resource, 057 * or {@code null} if a raw {@link HttpServletResponse#SC_UNAUTHORIZED} response should be issued (401 Unauthorized). 058 */ 059 public String getUnauthorizedUrl() { 060 return unauthorizedUrl; 061 } 062 063 /** 064 * Sets the URL to which users should be redirected if they are denied access to an underlying path or resource. 065 * <p/> 066 * If the value is {@code null} a raw {@link HttpServletResponse#SC_UNAUTHORIZED} response will 067 * be issued (401 Unauthorized), retaining default web server behavior. 068 * <p/> 069 * Unless overridden by calling this method, the default value is {@code null}. If desired, you can specify a 070 * meaningful path within your application if you would like to show the user a 'nice' page in the event of 071 * unauthorized access. 072 * 073 * @param unauthorizedUrl the URL to which users should be redirected if they are denied access to an underlying 074 * path or resource, or {@code null} to a ensure raw {@link HttpServletResponse#SC_UNAUTHORIZED} response is 075 * issued (401 Unauthorized). 076 */ 077 public void setUnauthorizedUrl(String unauthorizedUrl) { 078 this.unauthorizedUrl = unauthorizedUrl; 079 } 080 081 /** 082 * Handles the response when access has been denied. It behaves as follows: 083 * <ul> 084 * <li>If the {@code Subject} is unknown<sup><a href="#known">[1]</a></sup>: 085 * <ol><li>The incoming request will be saved and they will be redirected to the login page for authentication 086 * (via the {@link #saveRequestAndRedirectToLogin(javax.servlet.ServletRequest, javax.servlet.ServletResponse)} 087 * method).</li> 088 * <li>Once successfully authenticated, they will be redirected back to the originally attempted page.</li></ol> 089 * </li> 090 * <li>If the Subject is known:</li> 091 * <ol> 092 * <li>The HTTP {@link HttpServletResponse#SC_UNAUTHORIZED} header will be set (401 Unauthorized)</li> 093 * <li>If the {@link #getUnauthorizedUrl() unauthorizedUrl} has been configured, a redirect will be issued to that 094 * URL. Otherwise the 401 response is rendered normally</li> 095 * </ul> 096 * <code><a name="known">[1]</a></code>: A {@code Subject} is 'known' when 097 * <code>subject.{@link org.apache.shiro.subject.Subject#getPrincipal() getPrincipal()}</code> is not {@code null}, 098 * which implicitly means that the subject is either currently authenticated or they have been remembered via 099 * 'remember me' services. 100 * 101 * @param request the incoming <code>ServletRequest</code> 102 * @param response the outgoing <code>ServletResponse</code> 103 * @return {@code false} always for this implementation. 104 * @throws IOException if there is any servlet error. 105 */ 106 protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { 107 108 Subject subject = getSubject(request, response); 109 // If the subject isn't identified, redirect to login URL 110 if (subject.getPrincipal() == null) { 111 saveRequestAndRedirectToLogin(request, response); 112 } else { 113 // If subject is known but not authorized, redirect to the unauthorized URL if there is one 114 // If no unauthorized URL is specified, just return an unauthorized HTTP status code 115 String unauthorizedUrl = getUnauthorizedUrl(); 116 //SHIRO-142 - ensure that redirect _or_ error code occurs - both cannot happen due to response commit: 117 if (StringUtils.hasText(unauthorizedUrl)) { 118 WebUtils.issueRedirect(request, response, unauthorizedUrl); 119 } else { 120 WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED); 121 } 122 } 123 return false; 124 } 125 126}