View Javadoc
1   /*
2    * Copyright (c) 2002-2025, 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.web.xpages;
35  
36  import java.io.File;
37  import java.io.FileInputStream;
38  import java.io.FileOutputStream;
39  import java.io.IOException;
40  import java.io.InputStream;
41  import java.io.OutputStream;
42  import java.security.SecureRandom;
43  import java.util.Arrays;
44  import java.util.Properties;
45  import java.util.Random;
46  
47  import javax.servlet.http.HttpServletRequest;
48  
49  import org.springframework.mock.web.MockHttpServletRequest;
50  
51  import fr.paris.lutece.portal.business.page.Page;
52  import fr.paris.lutece.portal.business.style.PageTemplateHome;
53  import fr.paris.lutece.portal.service.init.LuteceInitException;
54  import fr.paris.lutece.portal.service.page.IPageService;
55  import fr.paris.lutece.portal.service.plugin.Plugin;
56  import fr.paris.lutece.portal.service.portal.PortalService;
57  import fr.paris.lutece.portal.service.security.LuteceUser;
58  import fr.paris.lutece.portal.service.security.MokeLuteceAuthentication;
59  import fr.paris.lutece.portal.service.security.SecurityService;
60  import fr.paris.lutece.portal.service.spring.SpringContextService;
61  import fr.paris.lutece.portal.service.util.AppPropertiesService;
62  import fr.paris.lutece.test.LuteceTestCase;
63  
64  /**
65   * SiteMap Test Class
66   */
67  public class SiteMapAppTest extends LuteceTestCase
68  {
69      private static final String ROLE1 = "ROLE1";
70      private static final String ROLE2 = "ROLE2";
71  
72      /**
73       * Test of getPage method, of class fr.paris.lutece.portal.web.xpages.SiteMapApp.
74       */
75      public void testGetPage( )
76      {
77          MockHttpServletRequest request = new MockHttpServletRequest( );
78  
79          int nMode = 0;
80          Plugin plugin = null;
81          SiteMapApp instance = new SiteMapApp( );
82  
83          XPage result = instance.getPage( request, nMode, plugin );
84          assertNotNull( result );
85      }
86  
87      public void testGetPageMod( )
88      {
89          HttpServletRequest request = new MockHttpServletRequest( );
90  
91          // determine a random page name
92          String randomPageName = "page" + new SecureRandom( ).nextLong( );
93  
94          // get the site map
95          SiteMapApp instance = new SiteMapApp( );
96          XPage sitemap = instance.getPage( request, 0, null );
97          assertFalse( "Site map should not contain not yet created page with name " + randomPageName, sitemap.getContent( ).contains( randomPageName ) );
98  
99          // create the page
100         Page page = new Page( );
101         page.setParentPageId( PortalService.getRootPageId( ) );
102         page.setPageTemplateId( PageTemplateHome.getPageTemplatesList( ).get( 0 ).getId( ) );
103         page.setName( randomPageName );
104 
105         IPageService pageService = (IPageService) SpringContextService.getBean( "pageService" );
106         pageService.createPage( page );
107         // get the site map
108         sitemap = instance.getPage( request, 0, null );
109         assertTrue( "Site map should contain page with name " + randomPageName, sitemap.getContent( ).contains( randomPageName ) );
110         // change the page name
111         randomPageName = randomPageName + "_mod";
112         page.setName( randomPageName );
113         pageService.updatePage( page );
114         // get the site map
115         sitemap = instance.getPage( request, 0, null );
116         assertTrue( "Site map should contain page with the modified name " + randomPageName, sitemap.getContent( ).contains( randomPageName ) );
117         // remove the page
118         pageService.removePage( page.getId( ) );
119         // get the site map
120         sitemap = instance.getPage( request, 0, null );
121         assertFalse( "Site map should not contain page with name " + randomPageName + " anymore", sitemap.getContent( ).contains( randomPageName ) );
122     }
123 
124     public void testPageVisibility( ) throws IOException, LuteceInitException
125     {
126         // create pages
127         final Random rand = new SecureRandom( );
128         Page pageNoRole = createPage( "page." + rand.nextLong( ) );
129         Page pageRole1 = createPage( "page.role1." + rand.nextLong( ), ROLE1 );
130         Page pageRole2 = createPage( "page.role2." + rand.nextLong( ), ROLE2 );
131 
132         boolean authStatus = enableAuthentication( );
133         boolean cacheStatus = enableSiteMapCacheService( );
134 
135         try
136         {
137             SiteMapApp instance = new SiteMapApp( );
138 
139             // test twice to test the cache
140             for ( int i = 0; i < 2; i++ )
141             {
142                 // test menu content with no user
143                 HttpServletRequest request = new MockHttpServletRequest( );
144                 XPage sitemap = instance.getPage( request, 0, null );
145                 assertTrue( "Site map should contain page not associated with a role named " + pageNoRole.getName( ) + " (call " + ( i + 1 ) + ")",
146                         sitemap.getContent( ).contains( pageNoRole.getName( ) ) );
147                 assertFalse( "Site map should not contain page associated with role " + ROLE1 + " named " + pageRole1.getName( ) + " (call " + ( i + 1 ) + ")",
148                         sitemap.getContent( ).contains( pageRole1.getName( ) ) );
149                 assertFalse( "Site map should not contain page associated with role " + ROLE2 + " named " + pageRole2.getName( ) + " (call " + ( i + 1 ) + ")",
150                         sitemap.getContent( ).contains( pageRole2.getName( ) ) );
151 
152                 // test menu content with no role
153                 @SuppressWarnings( "serial" )
154                 LuteceUser user = new LuteceUser( "junit", SecurityService.getInstance( ).getAuthenticationService( ) )
155                 {
156                     @Override
157                     public String getName( )
158                     {
159                         // user name is different on each call
160                         return "user" + rand.nextLong( );
161                     }
162                 };
163 
164                 request.getSession( ).setAttribute( "lutece_user", user );
165                 sitemap = instance.getPage( request, 0, null );
166                 assertTrue( "Site map should contain page not associated with a role named " + pageNoRole.getName( ) + " (call " + ( i + 1 ) + ")",
167                         sitemap.getContent( ).contains( pageNoRole.getName( ) ) );
168                 assertFalse( "Site map should not contain page associated with role " + ROLE1 + " named " + pageRole1.getName( ) + " (call " + ( i + 1 ) + ")",
169                         sitemap.getContent( ).contains( pageRole1.getName( ) ) );
170                 assertFalse( "Site map should not contain page associated with role " + ROLE2 + " named " + pageRole2.getName( ) + " (call " + ( i + 1 ) + ")",
171                         sitemap.getContent( ).contains( pageRole2.getName( ) ) );
172                 // test menu content with ROLE1
173                 user.setRoles( Arrays.asList( ROLE1 ) );
174                 sitemap = instance.getPage( request, 0, null );
175                 assertTrue( "Site map should contain page not associated with a role named " + pageNoRole.getName( ) + " (call " + ( i + 1 ) + ")",
176                         sitemap.getContent( ).contains( pageNoRole.getName( ) ) );
177                 assertTrue( "Site map should contain page associated with role " + ROLE1 + " named " + pageRole1.getName( ) + " (call " + ( i + 1 ) + ")",
178                         sitemap.getContent( ).contains( pageRole1.getName( ) ) );
179                 assertFalse( "Site map should not contain page associated with role " + ROLE2 + " named " + pageRole2.getName( ) + " (call " + ( i + 1 ) + ")",
180                         sitemap.getContent( ).contains( pageRole2.getName( ) ) );
181 
182                 // test menu content with ROLE2
183                 user.setRoles( Arrays.asList( ROLE2 ) );
184                 sitemap = instance.getPage( request, 0, null );
185                 assertTrue( "Site map should contain page not associated with a role named " + pageNoRole.getName( ) + " (call " + ( i + 1 ) + ")",
186                         sitemap.getContent( ).contains( pageNoRole.getName( ) ) );
187                 assertFalse( "Site map should not contain page associated with role " + ROLE1 + " named " + pageRole1.getName( ) + " (call " + ( i + 1 ) + ")",
188                         sitemap.getContent( ).contains( pageRole1.getName( ) ) );
189                 assertTrue( "Site map should contain page associated with role " + ROLE2 + " named " + pageRole2.getName( ) + " (call " + ( i + 1 ) + ")",
190                         sitemap.getContent( ).contains( pageRole2.getName( ) ) );
191 
192                 // test menu content with ROLE1 and ROLE2
193                 user.setRoles( Arrays.asList( ROLE1, ROLE2 ) );
194                 sitemap = instance.getPage( request, 0, null );
195                 assertTrue( "Site map should contain page not associated with a role named " + pageNoRole.getName( ) + " (call " + ( i + 1 ) + ")",
196                         sitemap.getContent( ).contains( pageNoRole.getName( ) ) );
197                 assertTrue( "Site map should contain page associated with role " + ROLE1 + " named " + pageRole1.getName( ) + " (call " + ( i + 1 ) + ")",
198                         sitemap.getContent( ).contains( pageRole1.getName( ) ) );
199                 assertTrue( "Site map should contain page associated with role " + ROLE2 + " named " + pageRole2.getName( ) + " (call " + ( i + 1 ) + ")",
200                         sitemap.getContent( ).contains( pageRole2.getName( ) ) );
201 
202                 // test menu content with ROLE2 and ROLE1
203                 user.setRoles( Arrays.asList( ROLE2, ROLE1 ) );
204 
205                 XPage sitemap2 = instance.getPage( request, 0, null );
206                 assertTrue( "Role order should not matter to the cache (call " + ( i + 1 ) + ")", sitemap.getContent( ) == sitemap2.getContent( ) );
207             }
208         }
209         finally
210         {
211             // cleanup
212             restoreAuthentication( authStatus );
213             restoreSiteMapCacheService( cacheStatus );
214 
215             IPageService pageService = (IPageService) SpringContextService.getBean( "pageService" );
216             pageService.removePage( pageNoRole.getId( ) );
217             pageService.removePage( pageRole1.getId( ) );
218             pageService.removePage( pageRole2.getId( ) );
219         }
220     }
221 
222     private void restoreSiteMapCacheService( boolean status )
223     {
224         SiteMapCacheService.getInstance( ).enableCache( status );
225     }
226 
227     private boolean enableSiteMapCacheService( )
228     {
229         boolean status = SiteMapCacheService.getInstance( ).isCacheEnable( );
230         SiteMapCacheService.getInstance( ).enableCache( true );
231 
232         return status;
233     }
234 
235     private void restoreAuthentication( boolean status ) throws IOException, LuteceInitException
236     {
237         if ( !status )
238         {
239             File luteceProperties = new File( getResourcesDir( ), "WEB-INF/conf/lutece.properties" );
240             Properties props = new Properties( );
241             InputStream is = new FileInputStream( luteceProperties );
242             props.load( is );
243             is.close( );
244             props.remove( "mylutece.authentication.enable" );
245             props.remove( "mylutece.authentication.class" );
246 
247             OutputStream os = new FileOutputStream( luteceProperties );
248             props.store( os, "saved for junit " + this.getClass( ).getCanonicalName( ) );
249             os.close( );
250             AppPropertiesService.reloadAll( );
251             SecurityService.init( );
252         }
253     }
254 
255     private boolean enableAuthentication( ) throws IOException, LuteceInitException
256     {
257         boolean status = SecurityService.isAuthenticationEnable( );
258 
259         if ( !status )
260         {
261             File luteceProperties = new File( getResourcesDir( ), "WEB-INF/conf/lutece.properties" );
262             Properties props = new Properties( );
263             InputStream is = new FileInputStream( luteceProperties );
264             props.load( is );
265             is.close( );
266             props.setProperty( "mylutece.authentication.enable", "true" );
267             props.setProperty( "mylutece.authentication.class", MokeLuteceAuthentication.class.getName( ) );
268 
269             OutputStream os = new FileOutputStream( luteceProperties );
270             props.store( os, "saved for junit " + this.getClass( ).getCanonicalName( ) );
271             os.close( );
272             AppPropertiesService.reloadAll( );
273             SecurityService.init( );
274         }
275 
276         return status;
277     }
278 
279     private Page createPage( String pageName, String role )
280     {
281         Page page = new Page( );
282         page.setParentPageId( PortalService.getRootPageId( ) );
283         page.setName( pageName );
284         page.setPageTemplateId( PageTemplateHome.getPageTemplatesList( ).get( 0 ).getId( ) );
285 
286         if ( role != null )
287         {
288             page.setRole( role );
289         }
290 
291         IPageService pageService = (IPageService) SpringContextService.getBean( "pageService" );
292         pageService.createPage( page );
293 
294         return page;
295     }
296 
297     private Page createPage( String pageName )
298     {
299         return createPage( pageName, null );
300     }
301 }