/**
* Copyright (c) 2008-2011 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
*
* This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
* Public License Version 3 as published by the Free Software Foundation.
*
* 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 Affero General Public License Version 3
* for more details.
*
* You should have received a copy of the GNU Affero General Public License Version 3 along with this program. If not, see
* http://www.gnu.org/licenses.
*
* Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
* Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
* All other trademarks are the property of their respective owners.
*/
package org.sonatype.nexus.proxy.router;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import junit.framework.Assert;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.sonatype.nexus.configuration.application.ApplicationConfiguration;
import org.sonatype.nexus.configuration.model.CRepository;
import org.sonatype.nexus.configuration.model.DefaultCRepository;
import org.sonatype.nexus.proxy.AbstractNexusTestCase;
import org.sonatype.nexus.proxy.ResourceStoreRequest;
import org.sonatype.nexus.proxy.item.StorageCollectionItem;
import org.sonatype.nexus.proxy.item.StorageItem;
import org.sonatype.nexus.proxy.maven.maven1.M1LayoutedM2ShadowRepositoryConfiguration;
import org.sonatype.nexus.proxy.maven.maven1.M1Repository;
import org.sonatype.nexus.proxy.maven.maven2.M2GroupRepository;
import org.sonatype.nexus.proxy.maven.maven2.M2LayoutedM1ShadowRepository;
import org.sonatype.nexus.proxy.maven.maven2.M2Repository;
import org.sonatype.nexus.proxy.maven.maven2.Maven2ContentClass;
import org.sonatype.nexus.proxy.registry.RepositoryRegistry;
import org.sonatype.nexus.proxy.repository.GroupRepository;
import org.sonatype.nexus.proxy.repository.Repository;
import org.sonatype.nexus.proxy.repository.ShadowRepository;
import org.sonatype.nexus.proxy.target.Target;
import org.sonatype.nexus.proxy.target.TargetRegistry;
import org.sonatype.nexus.security.WebSecurityUtil;
import org.sonatype.security.SecuritySystem;
import org.sonatype.security.authentication.AuthenticationException;
public class DefaultRepositoryRouterTest
extends AbstractNexusTestCase
{
private RepositoryRouter router = null;
private RepositoryRegistry repositoryRegistry = null;
private SecuritySystem securitySystem = null;
private ApplicationConfiguration applicationConfiguration;
@Override
protected void setUp()
throws Exception
{
super.setUp();
applicationConfiguration = this.lookup( ApplicationConfiguration.class );
applicationConfiguration.saveConfiguration();
this.router = this.lookup( RepositoryRouter.class );
this.repositoryRegistry = this.lookup( RepositoryRegistry.class );
this.buildRepository( "repo1", true ).getCurrentCoreConfiguration();
this.buildRepository( "repo2", true );
this.buildRepository( "repo3-notexposed", false );
this.buildGroupRepository( "group1", true );
this.buildGroupRepository( "group2", true );
this.buildGroupRepository( "group3-notexposed", false );
this.buildShadowRepository( "repo3", true );
this.buildShadowRepository( "repo4", true );
this.buildShadowRepository( "repo5-notexposed", false );
// copy the security-configuration
String resource = this.getClass().getName().replaceAll( "\\.", "\\/" ) + "-security-configuration.xml";
URL url = Thread.currentThread().getContextClassLoader().getResource( resource );
FileUtils.copyURLToFile( url, new File( getConfHomeDir(), "security-configuration.xml" ) );
// create a target
TargetRegistry targetRegistry = this.lookup( TargetRegistry.class );
Target t1 =
new Target( "maven2-all", "All (Maven2)", new Maven2ContentClass(), Arrays.asList( new String[] { ".*" } ) );
targetRegistry.addRepositoryTarget( t1 );
// flush changes
applicationConfiguration.saveConfiguration();
// setup security
this.securitySystem = this.lookup( SecuritySystem.class );
this.securitySystem.start();
}
public void testRouterWithViewAccess()
throws Exception
{
Subject subject = this.loginUser( "repo1user" );
ResourceStoreRequest request = new ResourceStoreRequest( "/repositories/" );
StorageItem item = router.retrieveItem( request );
StorageCollectionItem collectionItem = (StorageCollectionItem) item;
// this user only has access to repo1, that is all they should see
Assert.assertEquals( "User should only have access to 'repo1'", 1, collectionItem.list().size() );
Assert.assertEquals( "repo1", collectionItem.list().iterator().next().getName() );
// logout user
this.securitySystem.logout( subject );
}
public void testRouterWithNoViewAccess()
throws Exception
{
Subject subject = this.loginUser( "repo1userNoView" );
ResourceStoreRequest request = new ResourceStoreRequest( "/repositories/" );
StorageItem item = router.retrieveItem( request );
StorageCollectionItem collectionItem = (StorageCollectionItem) item;
// this user only has access to repo1, that is all they should see
Assert.assertEquals( "User should not have access to any repos", 0, collectionItem.list().size() );
// logout user
this.securitySystem.logout( subject );
}
public void testFilterOutNonExposedRepositories()
throws Exception
{
Subject subject = this.loginUser( "admin" );
ResourceStoreRequest request = new ResourceStoreRequest( "/repositories/" );
StorageItem item = router.retrieveItem( request );
StorageCollectionItem collectionItem = (StorageCollectionItem) item;
Assert.assertEquals( "User should see 8 repositories", 8, collectionItem.list().size() ); // we create a new
// repo for each
// shadow
List<String> repoIds = new ArrayList<String>();
for ( StorageItem tmpItem : collectionItem.list() )
{
repoIds.add( tmpItem.getName() );
}
// now check them all
Assert.assertTrue( repoIds.contains( "repo1" ) );
Assert.assertTrue( repoIds.contains( "repo2" ) );
Assert.assertFalse( repoIds.contains( "repo3-notexposed" ) );
Assert.assertTrue( repoIds.contains( "group1" ) );
Assert.assertTrue( repoIds.contains( "group2" ) );
Assert.assertFalse( repoIds.contains( "group3-notexposed" ) );
Assert.assertTrue( repoIds.contains( "repo3" ) );
Assert.assertTrue( repoIds.contains( "repo4" ) );
Assert.assertFalse( repoIds.contains( "repo5-notexposed" ) );
Assert.assertTrue( repoIds.contains( "repo3-shadow" ) );
Assert.assertTrue( repoIds.contains( "repo4-shadow" ) );
Assert.assertFalse( repoIds.contains( "repo5-notexposed-shadow" ) );
// logout user
this.securitySystem.logout( subject );
}
public void testFilterOutNonExposedGroups()
throws Exception
{
Subject subject = this.loginUser( "admin" );
ResourceStoreRequest request = new ResourceStoreRequest( "/shadows/" );
StorageItem item = router.retrieveItem( request );
StorageCollectionItem collectionItem = (StorageCollectionItem) item;
Assert.assertEquals( "User should see 2 groups", 2, collectionItem.list().size() );
List<String> repoIds = new ArrayList<String>();
for ( StorageItem tmpItem : collectionItem.list() )
{
repoIds.add( tmpItem.getName() );
}
// now check them all
Assert.assertTrue( repoIds.contains( "repo3-shadow" ) );
Assert.assertTrue( repoIds.contains( "repo4-shadow" ) );
Assert.assertFalse( repoIds.contains( "repo5-notexposed-shadow" ) );
// logout user
this.securitySystem.logout( subject );
}
public void testFilterOutNonExposedShadows()
throws Exception
{
Subject subject = this.loginUser( "admin" );
ResourceStoreRequest request = new ResourceStoreRequest( "/groups/" );
StorageItem item = router.retrieveItem( request );
StorageCollectionItem collectionItem = (StorageCollectionItem) item;
Assert.assertEquals( "User should see 2 groups", 2, collectionItem.list().size() );
List<String> repoIds = new ArrayList<String>();
for ( StorageItem tmpItem : collectionItem.list() )
{
repoIds.add( tmpItem.getName() );
}
// now check them all
Assert.assertTrue( repoIds.contains( "group1" ) );
Assert.assertTrue( repoIds.contains( "group2" ) );
Assert.assertFalse( repoIds.contains( "group3-notexposed" ) );
// logout user
this.securitySystem.logout( subject );
}
private Repository buildRepository( String repoId, boolean exposed )
throws Exception
{
M2Repository repo = (M2Repository) this.lookup( Repository.class, "maven2" );
CRepository repoConfig = new DefaultCRepository();
repoConfig.setId( repoId );
repoConfig.setExposed( exposed );
repoConfig.setProviderRole( Repository.class.getName() );
repoConfig.setProviderHint( "maven2" );
repo.configure( repoConfig );
this.repositoryRegistry.addRepository( repo );
this.applicationConfiguration.getConfigurationModel().addRepository( repoConfig );
return repo;
}
private Repository buildGroupRepository( String repoId, boolean exposed )
throws Exception
{
M2GroupRepository repo = (M2GroupRepository) this.lookup( GroupRepository.class, "maven2" );
CRepository repoConfig = new DefaultCRepository();
repoConfig.setId( repoId );
repoConfig.setExposed( exposed );
repoConfig.setProviderRole( GroupRepository.class.getName() );
repoConfig.setProviderHint( "maven2" );
repo.configure( repoConfig );
this.repositoryRegistry.addRepository( repo );
this.applicationConfiguration.getConfigurationModel().addRepository( repoConfig );
return repo;
}
private Repository buildShadowRepository( String repoId, boolean exposed )
throws Exception
{
M1Repository repo = (M1Repository) this.lookup( Repository.class, "maven1" );
CRepository repoConfig = new DefaultCRepository();
repoConfig.setId( repoId );
repoConfig.setExposed( exposed );
repoConfig.setIndexable( false );
repoConfig.setProviderRole( Repository.class.getName() );
repoConfig.setProviderHint( "maven1" );
repo.configure( repoConfig );
this.repositoryRegistry.addRepository( repo );
this.applicationConfiguration.getConfigurationModel().addRepository( repoConfig );
// now for the shadow
M2LayoutedM1ShadowRepository shadow =
(M2LayoutedM1ShadowRepository) this.lookup( ShadowRepository.class, "m1-m2-shadow" );
CRepository shadowConfig = new DefaultCRepository();
shadowConfig.setId( repoId + "-shadow" );
shadowConfig.setExposed( exposed );
shadowConfig.setProviderRole( ShadowRepository.class.getName() );
shadowConfig.setProviderHint( "m2-m1-shadow" );
shadowConfig.setIndexable( false );
Xpp3Dom exRepo = new Xpp3Dom( "externalConfiguration" );
shadowConfig.setExternalConfiguration( exRepo );
M1LayoutedM2ShadowRepositoryConfiguration exRepoConf = new M1LayoutedM2ShadowRepositoryConfiguration( exRepo );
exRepoConf.setMasterRepositoryId( repo.getId() );
shadow.configure( shadowConfig );
// shadow.
this.repositoryRegistry.addRepository( shadow );
this.applicationConfiguration.getConfigurationModel().addRepository( shadowConfig );
return repo;
}
private Subject loginUser( String username )
throws AuthenticationException
{
WebSecurityUtil.setupWebContext( username );
return this.securitySystem.login( new UsernamePasswordToken( username, "" ) );
}
}