View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.portal.service.filter;
35  
36  import java.io.IOException;
37  
38  import javax.servlet.Filter;
39  import javax.servlet.FilterChain;
40  import javax.servlet.FilterConfig;
41  import javax.servlet.ServletException;
42  import javax.servlet.ServletRequest;
43  import javax.servlet.ServletResponse;
44  import javax.servlet.http.HttpServletRequest;
45  import javax.servlet.http.HttpServletResponse;
46  
47  import fr.paris.lutece.portal.service.util.AppLogService;
48  import fr.paris.lutece.util.sql.TransactionManager;
49  
50  /**
51   * MainFilter
52   */
53  public class MainFilter implements Filter
54  {
55      /**
56       * {@inheritDoc}
57       */
58      public void init( FilterConfig config ) throws ServletException
59      {
60          FilterService.setServletContext( config.getServletContext( ) );
61      }
62  
63      /**
64       * {@inheritDoc}
65       */
66      public void doFilter( ServletRequest requestServlet, ServletResponse responseServlet, FilterChain chain ) throws IOException, ServletException
67      {
68          AppLogService.debug( "MainFilter : doFilter()" );
69  
70          HttpServletRequest request = (HttpServletRequest) requestServlet;
71          HttpServletResponse response = (HttpServletResponse) responseServlet;
72          LuteceFilterChainlterChain.html#LuteceFilterChain">LuteceFilterChain chainPluginsFilters = new LuteceFilterChain( );
73  
74          for ( LuteceFilter filter : FilterService.getInstance( ).getFilters( ) )
75          {
76              AppLogService.debug( "PluginFilter : {} - url pattern : {}", filter.getName( ), filter.getMappingUrlPattern( ) );
77  
78              // Catch exception for each filter to execute all chain
79              try
80              {
81                  // Checks mapping and plugin status
82                  if ( matchMapping( filter, request ) && filter.getPlugin( ).isInstalled( ) )
83                  {
84                      chainPluginsFilters.setFollowChain( false );
85                      filter.getFilter( ).doFilter( request, response, chainPluginsFilters );
86  
87                      if ( !chainPluginsFilters.shouldFollowChain( ) )
88                      {
89                          // The filter didn't call chain.doFilter so the chain should be interrupted
90                          return;
91                      }
92  
93                      // the filter may have changed (wrapped) the request [like CAS filter] or the
94                      // response
95                      request = (HttpServletRequest) chainPluginsFilters.getRequest( );
96                      response = (HttpServletResponse) chainPluginsFilters.getResponse( );
97                  }
98              }
99              catch( Exception e )
100             {
101                 AppLogService.error( "Error execution doFilter method - Filter {}", filter.getName( ), e );
102             }
103         }
104 
105         // Follow the standard filters chain
106         chain.doFilter( request, response );
107         // We check that some transactions is not still running for the current thread
108         TransactionManager.rollBackEveryTransaction( );
109     }
110 
111     /**
112      * {@inheritDoc}
113      */
114     public void destroy( )
115     {
116         for ( LuteceFilter filter : FilterService.getInstance( ).getFilters( ) )
117         {
118             // Catch exception for each filter to execute all chain
119             try
120             {
121                 // Checks mapping and plugin status
122                 if ( filter.getPlugin( ).isInstalled( ) )
123                 {
124                     filter.getFilter( ).destroy( );
125                 }
126             }
127             catch( Exception e )
128             {
129                 AppLogService.error( "Error execution destroy() method - Filter {} ", filter.getName( ), e );
130             }
131         }
132     }
133 
134     /**
135      * Check the mapping of the request with an url pattern
136      * 
137      * @param filter
138      *            The filter
139      * @param request
140      *            The request
141      * @return True if the request match the url pattern
142      */
143     boolean matchMapping( LuteceFilter filter, HttpServletRequest request )
144     {
145         return matchFilterUrl( filter.getMappingUrlPattern( ), request.getServletPath( ) );
146     }
147 
148     /**
149      * Check the mapping of the request with an url pattern according servlet specifications 2.3 rules
150      * 
151      * @param strUrlPattern
152      *            The filter url pattern
153      * @param strRequestUrl
154      *            The request Url
155      * @return True if the request match the url pattern
156      *
157      *         Algorithm comming from tomcat6
158      */
159     boolean matchFilterUrl( String strUrlPattern, String strRequestUrl )
160     {
161         if ( strUrlPattern == null )
162         {
163             return ( false ); // Case 1 - Exact Match
164         }
165 
166         if ( strUrlPattern.equals( strRequestUrl ) )
167         {
168             return ( true ); // Case 2 - Path Match ("/.../*")
169         }
170 
171         if ( strUrlPattern.equals( "/*" ) )
172         {
173             return ( true );
174         }
175 
176         if ( strUrlPattern.endsWith( "/*" ) )
177         {
178             if ( strUrlPattern.regionMatches( 0, strRequestUrl, 0, strUrlPattern.length( ) - 2 )
179                     && ( strRequestUrl.length( ) == ( strUrlPattern.length( ) - 2 ) || '/' == strRequestUrl.charAt( strUrlPattern.length( ) - 2 ) ) )
180             {
181                 return ( true );
182             }
183 
184             return ( false );
185         }
186 
187         // Case 3 - Extension Match
188         if ( strUrlPattern.startsWith( "*." ) )
189         {
190             int slash = strRequestUrl.lastIndexOf( '/' );
191             int period = strRequestUrl.lastIndexOf( '.' );
192 
193             if ( ( slash >= 0 ) && ( period > slash ) && ( period != ( strRequestUrl.length( ) - 1 ) )
194                     && ( ( strRequestUrl.length( ) - period ) == ( strUrlPattern.length( ) - 1 ) ) )
195             {
196                 return ( strUrlPattern.regionMatches( 2, strRequestUrl, period + 1, strUrlPattern.length( ) - 2 ) );
197             }
198         }
199 
200         // Case 4 - "Default" Match
201         return ( false ); // NOTE - Not relevant for selecting filters
202     }
203 }