From 2262565505e91e36bb1fab985d46d9f3d878fa0d Mon Sep 17 00:00:00 2001 From: "Maria Odea B. Ching" Date: Mon, 6 Oct 2008 09:05:09 +0000 Subject: [PATCH] merged from archiva-security-fix trunk changes: -fix security issue -added RepositoryServletSecurityTest and ArchivaServletAuthenticatorTest test cases git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@702027 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/ArchivaServletAuthenticator.java | 12 +- .../archiva/security/ArchivaXworkUser.java | 5 + .../security/ServletAuthenticator.java | 36 +- .../security/AbstractSecurityTest.java | 126 ++++ .../ArchivaServletAuthenticatorTest.java | 224 +++++++ .../security/DefaultUserRepositoriesTest.java | 105 +--- .../ArchivaServletAuthenticatorTest.xml | 202 +++++++ .../webdav/ArchivaDavResourceFactory.java | 54 +- .../webdav/ArchivaDavSessionProvider.java | 5 +- .../webdav/ArchivaDavSessionProviderTest.java | 2 +- .../webdav/RepositoryServletSecurityTest.java | 545 +++++++++++++++++- .../repository-servlet-security-test/web.xml | 45 ++ .../webdav/RepositoryServletSecurityTest.xml | 193 ++----- pom.xml | 6 + 14 files changed, 1285 insertions(+), 275 deletions(-) create mode 100644 archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/AbstractSecurityTest.java create mode 100644 archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/ArchivaServletAuthenticatorTest.java create mode 100644 archiva-modules/archiva-web/archiva-security/src/test/resources/org/apache/maven/archiva/security/ArchivaServletAuthenticatorTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webdav/src/test/resources/WEB-INF/repository-servlet-security-test/web.xml diff --git a/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaServletAuthenticator.java b/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaServletAuthenticator.java index 31d1245c9..7059598df 100644 --- a/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaServletAuthenticator.java +++ b/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaServletAuthenticator.java @@ -93,11 +93,18 @@ public class ArchivaServletAuthenticator return true; } - public boolean isAuthorized( String principal, String repoId ) + public boolean isAuthorized( String principal, String repoId, boolean isWriteRequest ) throws UnauthorizedException { try { + String permission = ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS; + + if ( isWriteRequest ) + { + permission = ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD; + } + User user = securitySystem.getUserManager().findUser( principal ); if ( user.isLocked() ) { @@ -107,8 +114,7 @@ public class ArchivaServletAuthenticator AuthenticationResult authn = new AuthenticationResult( true, principal, null ); SecuritySession securitySession = new DefaultSecuritySession( authn, user ); - return securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS, - repoId ); + return securitySystem.isAuthorized( securitySession, permission, repoId ); } catch ( UserNotFoundException e ) { diff --git a/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaXworkUser.java b/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaXworkUser.java index 4c07a0cf4..c03405425 100644 --- a/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaXworkUser.java +++ b/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaXworkUser.java @@ -85,4 +85,9 @@ public class ArchivaXworkUser return guest; } + + public void setGuest( String guesT ) + { + guest = guesT; + } } diff --git a/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ServletAuthenticator.java b/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ServletAuthenticator.java index 2edda8120..adc6ad1ab 100644 --- a/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ServletAuthenticator.java +++ b/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ServletAuthenticator.java @@ -35,12 +35,46 @@ import org.codehaus.plexus.redback.system.SecuritySession; */ public interface ServletAuthenticator { + /** + * Authentication check for users. + * + * @param request + * @param result + * @return + * @throws AuthenticationException + * @throws AccountLockedException + * @throws MustChangePasswordException + */ public boolean isAuthenticated( HttpServletRequest request, AuthenticationResult result ) throws AuthenticationException, AccountLockedException, MustChangePasswordException; + /** + * Authorization check for valid users. + * + * @param request + * @param securitySession + * @param repositoryId + * @param isWriteRequest + * @return + * @throws AuthorizationException + * @throws UnauthorizedException + */ public boolean isAuthorized( HttpServletRequest request, SecuritySession securitySession, String repositoryId, boolean isWriteRequest ) throws AuthorizationException, UnauthorizedException; - public boolean isAuthorized( String principal, String repoId ) + /** + * Authorization check specific for user guest, which doesn't go through + * HttpBasicAuthentication#getAuthenticationResult( HttpServletRequest request, HttpServletResponse response ) + * since no credentials are attached to the request. + * + * See also MRM-911 + * + * @param principal + * @param repoId + * @param isWriteRequest + * @return + * @throws UnauthorizedException + */ + public boolean isAuthorized( String principal, String repoId, boolean isWriteRequest ) throws UnauthorizedException; } diff --git a/archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/AbstractSecurityTest.java b/archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/AbstractSecurityTest.java new file mode 100644 index 000000000..399c87eed --- /dev/null +++ b/archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/AbstractSecurityTest.java @@ -0,0 +1,126 @@ +package org.apache.maven.archiva.security; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; + +import org.apache.commons.io.FileUtils; +import org.apache.maven.archiva.configuration.ArchivaConfiguration; +import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; +import org.codehaus.plexus.redback.rbac.RBACManager; +import org.codehaus.plexus.redback.role.RoleManager; +import org.codehaus.plexus.redback.system.SecuritySystem; +import org.codehaus.plexus.redback.users.User; +import org.codehaus.plexus.redback.users.UserManager; +import org.codehaus.plexus.spring.PlexusInSpringTestCase; + +/** + * AbstractSecurityTest + * + * @author Maria Odea Ching + * @version $Id: AbstractSecurityTest + */ +public abstract class AbstractSecurityTest + extends PlexusInSpringTestCase +{ + protected static final String USER_GUEST = "guest"; + + protected static final String USER_ADMIN = "admin"; + + protected static final String USER_ALPACA = "alpaca"; + + protected SecuritySystem securitySystem; + + private RBACManager rbacManager; + + protected RoleManager roleManager; + + private ArchivaConfiguration archivaConfiguration; + + protected UserRepositories userRepos; + + protected void setupRepository( String repoId ) + throws Exception + { + // Add repo to configuration. + ManagedRepositoryConfiguration repoConfig = new ManagedRepositoryConfiguration(); + repoConfig.setId( repoId ); + repoConfig.setName( "Testable repo <" + repoId + ">" ); + repoConfig.setLocation( getTestPath( "target/test-repo/" + repoId ) ); + archivaConfiguration.getConfiguration().addManagedRepository( repoConfig ); + + // Add repo roles to security. + userRepos.createMissingRepositoryRoles( repoId ); + } + + protected void assignRepositoryObserverRole( String principal, String repoId ) + throws Exception + { + roleManager.assignTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId, principal ); + } + + protected User createUser( String principal, String fullname ) + { + UserManager userManager = securitySystem.getUserManager(); + + User user = userManager.createUser( principal, fullname, principal + "@testable.archiva.apache.org" ); + securitySystem.getPolicy().setEnabled( false ); + userManager.addUser( user ); + securitySystem.getPolicy().setEnabled( true ); + + return user; + } + + @Override + public void setUp() + throws Exception + { + super.setUp(); + + File srcConfig = getTestFile( "src/test/resources/repository-archiva.xml" ); + File destConfig = getTestFile( "target/test-conf/archiva.xml" ); + + destConfig.getParentFile().mkdirs(); + destConfig.delete(); + + FileUtils.copyFile( srcConfig, destConfig ); + + securitySystem = (SecuritySystem) lookup( SecuritySystem.class, "testable" ); + rbacManager = (RBACManager) lookup( RBACManager.class, "memory" ); + roleManager = (RoleManager) lookup( RoleManager.class, "default" ); + userRepos = (UserRepositories) lookup( UserRepositories.class, "default" ); + archivaConfiguration = (ArchivaConfiguration) lookup( ArchivaConfiguration.class ); + + // Some basic asserts. + assertNotNull( securitySystem ); + assertNotNull( rbacManager ); + assertNotNull( roleManager ); + assertNotNull( userRepos ); + assertNotNull( archivaConfiguration ); + + // Setup Admin User. + User adminUser = createUser( USER_ADMIN, "Admin User" ); + roleManager.assignRole( ArchivaRoleConstants.TEMPLATE_SYSTEM_ADMIN, adminUser.getPrincipal().toString() ); + + // Setup Guest User. + User guestUser = createUser( USER_GUEST, "Guest User" ); + roleManager.assignRole( ArchivaRoleConstants.TEMPLATE_GUEST, guestUser.getPrincipal().toString() ); + } +} diff --git a/archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/ArchivaServletAuthenticatorTest.java b/archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/ArchivaServletAuthenticatorTest.java new file mode 100644 index 000000000..d100b88ac --- /dev/null +++ b/archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/ArchivaServletAuthenticatorTest.java @@ -0,0 +1,224 @@ +package org.apache.maven.archiva.security; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import javax.servlet.http.HttpServletRequest; + +import org.codehaus.plexus.redback.authentication.AuthenticationException; +import org.codehaus.plexus.redback.authentication.AuthenticationResult; +import org.codehaus.plexus.redback.authorization.UnauthorizedException; +import org.codehaus.plexus.redback.system.DefaultSecuritySession; +import org.codehaus.plexus.redback.system.SecuritySession; +import org.codehaus.plexus.redback.users.User; +import org.codehaus.plexus.redback.users.UserManager; + +import org.easymock.MockControl; + +/** + * ArchivaServletAuthenticatorTest + * + * @author Maria Odea Ching + * @version + */ +public class ArchivaServletAuthenticatorTest + extends AbstractSecurityTest +{ + private ServletAuthenticator servletAuth; + + private MockControl httpServletRequestControl; + + private HttpServletRequest request; + + @Override + public void setUp() + throws Exception + { + super.setUp(); + + servletAuth = ( ServletAuthenticator ) lookup( ServletAuthenticator.class, "default" ); + + httpServletRequestControl = MockControl.createControl( HttpServletRequest.class ); + request = ( HttpServletRequest ) httpServletRequestControl.getMock(); + + setupRepository( "corporate" ); + } + + @Override + protected String getPlexusConfigLocation() + { + return "org/apache/maven/archiva/security/ArchivaServletAuthenticatorTest.xml"; + } + + protected void assignRepositoryManagerRole( String principal, String repoId ) + throws Exception + { + roleManager.assignTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, repoId, principal ); + } + + public void testIsAuthenticatedUserExists() + throws Exception + { + AuthenticationResult result = new AuthenticationResult( true, "user", null ); + boolean isAuthenticated = servletAuth.isAuthenticated( request, result ); + + assertTrue( isAuthenticated ); + } + + public void testIsAuthenticatedUserDoesNotExist() + throws Exception + { + AuthenticationResult result = new AuthenticationResult( false, "non-existing-user", null ); + try + { + servletAuth.isAuthenticated( request, result ); + fail( "Authentication exception should have been thrown." ); + } + catch ( AuthenticationException e ) + { + assertEquals( "User Credentials Invalid", e.getMessage() ); + } + } + + public void testIsAuthorizedUserHasWriteAccess() + throws Exception + { + createUser( USER_ALPACA, "Al 'Archiva' Paca" ); + + assignRepositoryManagerRole( USER_ALPACA, "corporate" ); + + UserManager userManager = securitySystem.getUserManager(); + User user = userManager.findUser( USER_ALPACA ); + + AuthenticationResult result = new AuthenticationResult( true, USER_ALPACA, null ); + + SecuritySession session = new DefaultSecuritySession( result, user ); + boolean isAuthorized = servletAuth.isAuthorized( request, session, "corporate", true ); + + assertTrue( isAuthorized ); + } + + public void testIsAuthorizedUserHasNoWriteAccess() + throws Exception + { + createUser( USER_ALPACA, "Al 'Archiva' Paca" ); + + assignRepositoryObserverRole( USER_ALPACA, "corporate" ); + + httpServletRequestControl.expectAndReturn( request.getRemoteAddr(), "192.168.111.111" ); + + UserManager userManager = securitySystem.getUserManager(); + User user = userManager.findUser( USER_ALPACA ); + + AuthenticationResult result = new AuthenticationResult( true, USER_ALPACA, null ); + + SecuritySession session = new DefaultSecuritySession( result, user ); + + httpServletRequestControl.replay(); + + try + { + servletAuth.isAuthorized( request, session, "corporate", true ); + fail( "UnauthorizedException should have been thrown." ); + } + catch ( UnauthorizedException e ) + { + assertEquals( "Access denied for repository corporate", e.getMessage() ); + } + + httpServletRequestControl.verify(); + } + + + public void testIsAuthorizedUserHasReadAccess() + throws Exception + { + createUser( USER_ALPACA, "Al 'Archiva' Paca" ); + + assignRepositoryObserverRole( USER_ALPACA, "corporate" ); + + UserManager userManager = securitySystem.getUserManager(); + User user = userManager.findUser( USER_ALPACA ); + + AuthenticationResult result = new AuthenticationResult( true, USER_ALPACA, null ); + + SecuritySession session = new DefaultSecuritySession( result, user ); + boolean isAuthorized = servletAuth.isAuthorized( request, session, "corporate", false ); + + assertTrue( isAuthorized ); + } + + public void testIsAuthorizedUserHasNoReadAccess() + throws Exception + { + createUser( USER_ALPACA, "Al 'Archiva' Paca" ); + + UserManager userManager = securitySystem.getUserManager(); + User user = userManager.findUser( USER_ALPACA ); + + AuthenticationResult result = new AuthenticationResult( true, USER_ALPACA, null ); + + SecuritySession session = new DefaultSecuritySession( result, user ); + try + { + servletAuth.isAuthorized( request, session, "corporate", false ); + fail( "UnauthorizedException should have been thrown." ); + } + catch ( UnauthorizedException e ) + { + assertEquals( "Access denied for repository corporate", e.getMessage() ); + } + } + + public void testIsAuthorizedGuestUserHasWriteAccess() + throws Exception + { + assignRepositoryManagerRole( USER_GUEST, "corporate" ); + boolean isAuthorized = servletAuth.isAuthorized( USER_GUEST, "corporate", true ); + + assertTrue( isAuthorized ); + } + + public void testIsAuthorizedGuestUserHasNoWriteAccess() + throws Exception + { + assignRepositoryObserverRole( USER_GUEST, "corporate" ); + + boolean isAuthorized = servletAuth.isAuthorized( USER_GUEST, "corporate", true ); + assertFalse( isAuthorized ); + } + + public void testIsAuthorizedGuestUserHasReadAccess() + throws Exception + { + assignRepositoryObserverRole( USER_GUEST, "corporate" ); + + boolean isAuthorized = servletAuth.isAuthorized( USER_GUEST, "corporate", false ); + + assertTrue( isAuthorized ); + } + + public void testIsAuthorizedGuestUserHasNoReadAccess() + throws Exception + { + boolean isAuthorized = servletAuth.isAuthorized( USER_GUEST, "corporate", false ); + + assertFalse( isAuthorized ); + } +} diff --git a/archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/DefaultUserRepositoriesTest.java b/archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/DefaultUserRepositoriesTest.java index ceb0a357c..a9f8c1897 100644 --- a/archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/DefaultUserRepositoriesTest.java +++ b/archiva-modules/archiva-web/archiva-security/src/test/java/org/apache/maven/archiva/security/DefaultUserRepositoriesTest.java @@ -19,19 +19,9 @@ package org.apache.maven.archiva.security; * under the License. */ -import java.io.File; import java.util.List; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; -import org.apache.maven.archiva.configuration.ArchivaConfiguration; -import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; -import org.codehaus.plexus.spring.PlexusInSpringTestCase; -import org.codehaus.plexus.redback.rbac.RBACManager; -import org.codehaus.plexus.redback.role.RoleManager; -import org.codehaus.plexus.redback.system.SecuritySystem; -import org.codehaus.plexus.redback.users.User; -import org.codehaus.plexus.redback.users.UserManager; /** * DefaultUserRepositoriesTest @@ -40,24 +30,14 @@ import org.codehaus.plexus.redback.users.UserManager; * @version $Id$ */ public class DefaultUserRepositoriesTest - extends PlexusInSpringTestCase -{ - private static final String USER_GUEST = "guest"; - - private static final String USER_ADMIN = "admin"; - - private static final String USER_ALPACA = "alpaca"; - - private SecuritySystem securitySystem; - - private RBACManager rbacManager; - - private RoleManager roleManager; - - private ArchivaConfiguration archivaConfiguration; - - private UserRepositories userRepos; - + extends AbstractSecurityTest +{ + @Override + protected String getPlexusConfigLocation() + { + return "org/apache/maven/archiva/security/DefaultUserRepositoriesTest.xml"; + } + public void testGetObservableRepositoryIds() throws Exception { @@ -98,78 +78,9 @@ public class DefaultUserRepositoriesTest } } - private void setupRepository( String repoId ) - throws Exception - { - // Add repo to configuration. - ManagedRepositoryConfiguration repoConfig = new ManagedRepositoryConfiguration(); - repoConfig.setId( repoId ); - repoConfig.setName( "Testable repo <" + repoId + ">" ); - repoConfig.setLocation( getTestPath( "target/test-repo/" + repoId ) ); - archivaConfiguration.getConfiguration().addManagedRepository( repoConfig ); - - // Add repo roles to security. - userRepos.createMissingRepositoryRoles( repoId ); - } - private void assignGlobalRepositoryObserverRole( String principal ) throws Exception { roleManager.assignRole( ArchivaRoleConstants.TEMPLATE_GLOBAL_REPOSITORY_OBSERVER, principal ); } - - private void assignRepositoryObserverRole( String principal, String repoId ) - throws Exception - { - roleManager.assignTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, repoId, principal ); - } - - private User createUser( String principal, String fullname ) - { - UserManager userManager = securitySystem.getUserManager(); - - User user = userManager.createUser( principal, fullname, principal + "@testable.archiva.apache.org" ); - securitySystem.getPolicy().setEnabled( false ); - userManager.addUser( user ); - securitySystem.getPolicy().setEnabled( true ); - - return user; - } - - @Override - protected void setUp() - throws Exception - { - super.setUp(); - - File srcConfig = getTestFile( "src/test/resources/repository-archiva.xml" ); - File destConfig = getTestFile( "target/test-conf/archiva.xml" ); - - destConfig.getParentFile().mkdirs(); - destConfig.delete(); - - FileUtils.copyFile( srcConfig, destConfig ); - - securitySystem = (SecuritySystem) lookup( SecuritySystem.class, "testable" ); - rbacManager = (RBACManager) lookup( RBACManager.class, "memory" ); - roleManager = (RoleManager) lookup( RoleManager.class, "default" ); - userRepos = (UserRepositories) lookup( UserRepositories.class, "default" ); - archivaConfiguration = (ArchivaConfiguration) lookup( ArchivaConfiguration.class ); - - // Some basic asserts. - assertNotNull( securitySystem ); - assertNotNull( rbacManager ); - assertNotNull( roleManager ); - assertNotNull( userRepos ); - assertNotNull( archivaConfiguration ); - - // Setup Admin User. - User adminUser = createUser( USER_ADMIN, "Admin User" ); - roleManager.assignRole( ArchivaRoleConstants.TEMPLATE_SYSTEM_ADMIN, adminUser.getPrincipal().toString() ); - - // Setup Guest User. - User guestUser = createUser( USER_GUEST, "Guest User" ); - roleManager.assignRole( ArchivaRoleConstants.TEMPLATE_GUEST, guestUser.getPrincipal().toString() ); - - } } diff --git a/archiva-modules/archiva-web/archiva-security/src/test/resources/org/apache/maven/archiva/security/ArchivaServletAuthenticatorTest.xml b/archiva-modules/archiva-web/archiva-security/src/test/resources/org/apache/maven/archiva/security/ArchivaServletAuthenticatorTest.xml new file mode 100644 index 000000000..adfb9b2b4 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-security/src/test/resources/org/apache/maven/archiva/security/ArchivaServletAuthenticatorTest.xml @@ -0,0 +1,202 @@ + + + + + + org.apache.maven.archiva.security.ServletAuthenticator + default + org.apache.maven.archiva.security.ArchivaServletAuthenticator + ArchivaServletAuthenticator + + + org.codehaus.plexus.redback.system.SecuritySystem + testable + securitySystem + + + + + + org.apache.maven.archiva.security.UserRepositories + default + org.apache.maven.archiva.security.DefaultUserRepositories + DefaultUserRepositories + + + org.codehaus.plexus.redback.system.SecuritySystem + testable + securitySystem + + + org.codehaus.plexus.redback.rbac.RBACManager + memory + rbacManager + + + org.codehaus.plexus.redback.role.RoleManager + default + roleManager + + + org.apache.maven.archiva.configuration.ArchivaConfiguration + archivaConfiguration + + + + + + org.codehaus.plexus.redback.system.SecuritySystem + testable + org.codehaus.plexus.redback.system.DefaultSecuritySystem + DefaultSecuritySystem: + + + org.codehaus.plexus.redback.authentication.AuthenticationManager + authnManager + + + org.codehaus.plexus.redback.authorization.Authorizer + rbac + authorizer + + + org.codehaus.plexus.redback.users.UserManager + memory + userManager + + + org.codehaus.plexus.redback.keys.KeyManager + memory + keyManager + + + org.codehaus.plexus.redback.policy.UserSecurityPolicy + policy + + + + + + org.codehaus.plexus.redback.authorization.Authorizer + rbac + org.codehaus.plexus.redback.authorization.rbac.RbacAuthorizer + RbacAuthorizer: + + + org.codehaus.plexus.redback.rbac.RBACManager + memory + manager + + + org.codehaus.plexus.redback.users.UserManager + memory + userManager + + + org.codehaus.plexus.redback.authorization.rbac.evaluator.PermissionEvaluator + default + evaluator + + + org.codehaus.plexus.redback.configuration.UserConfiguration + default + config + + + + + + org.codehaus.plexus.redback.authorization.rbac.evaluator.PermissionEvaluator + default + org.codehaus.plexus.redback.authorization.rbac.evaluator.DefaultPermissionEvaluator + + + org.codehaus.plexus.redback.users.UserManager + memory + userManager + + + + + + org.codehaus.plexus.redback.role.RoleManager + default + org.codehaus.plexus.redback.role.DefaultRoleManager + RoleProfileManager: + + + org.codehaus.plexus.redback.role.validator.RoleModelValidator + default + modelValidator + + + org.codehaus.plexus.redback.role.processor.RoleModelProcessor + default + modelProcessor + + + org.codehaus.plexus.redback.role.template.RoleTemplateProcessor + default + templateProcessor + + + org.codehaus.plexus.redback.rbac.RBACManager + memory + rbacManager + + + + + + org.codehaus.plexus.redback.role.processor.RoleModelProcessor + default + org.codehaus.plexus.redback.role.processor.DefaultRoleModelProcessor + DefaultRoleModelProcessor: inserts the components of the model that can be populated into the rbac manager + + + org.codehaus.plexus.redback.rbac.RBACManager + memory + rbacManager + + + + + + org.codehaus.plexus.redback.role.template.RoleTemplateProcessor + default + org.codehaus.plexus.redback.role.template.DefaultRoleTemplateProcessor + DefaultRoleTemplateProcessor: inserts the components of a template into the rbac manager + + + org.codehaus.plexus.redback.rbac.RBACManager + memory + rbacManager + + + + + + org.apache.maven.archiva.configuration.ArchivaConfiguration + org.apache.maven.archiva.configuration.DefaultArchivaConfiguration + + + org.codehaus.plexus.registry.Registry + configured + + + + + org.codehaus.plexus.registry.Registry + configured + org.codehaus.plexus.registry.commons.CommonsConfigurationRegistry + + + + + + + + + + diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java index 032f614fd..f56d7abe6 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java @@ -186,14 +186,14 @@ public class ArchivaDavResourceFactory { checkLocatorIsInstanceOfRepositoryLocator( locator ); ArchivaDavResourceLocator archivaLocator = (ArchivaDavResourceLocator) locator; - + RepositoryGroupConfiguration repoGroupConfig = archivaConfiguration.getConfiguration().getRepositoryGroupsAsMap().get( archivaLocator.getRepositoryId() ); List repositories = new ArrayList(); boolean isGet = WebdavMethodUtil.isReadMethod( request.getMethod() ); boolean isPut = WebdavMethodUtil.isWriteMethod( request.getMethod() ); - + if ( repoGroupConfig != null ) { if( WebdavMethodUtil.isWriteMethod( request.getMethod() ) ) @@ -230,7 +230,7 @@ public class ArchivaDavResourceFactory try { - managedRepository = getManagedRepository( repositoryId ); + managedRepository = getManagedRepository( repositoryId ); } catch ( DavException de ) { @@ -241,13 +241,13 @@ public class ArchivaDavResourceFactory DavResource resource = null; if ( !locator.getResourcePath().startsWith( ArchivaDavResource.HIDDEN_PATH_PREFIX ) ) - { + { if ( managedRepository != null ) { try { if( isAuthorized( request, repositoryId ) ) - { + { LogicalResource logicalResource = new LogicalResource( RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ) ); @@ -258,12 +258,12 @@ public class ArchivaDavResourceFactory if ( isPut ) { - resource = doPut( managedRepository, request, archivaLocator, logicalResource ); + resource = doPut( managedRepository, request, archivaLocator, logicalResource ); } } } catch ( DavException de ) - { + { e = de; continue; } @@ -273,11 +273,11 @@ public class ArchivaDavResourceFactory e = new DavException( HttpServletResponse.SC_NOT_FOUND, "Resource does not exist" ); } else - { + { availableResources.add( resource ); String logicalResource = RepositoryPathUtil.getLogicalResource( locator.getResourcePath() ); - resourcesInAbsolutePath.add( managedRepository.getRepoRoot() + logicalResource ); + resourcesInAbsolutePath.add( managedRepository.getRepoRoot() + logicalResource ); } } else @@ -491,15 +491,16 @@ public class ArchivaDavResourceFactory File rootDirectory = new File( managedRepository.getRepoRoot() ); File destDir = new File( rootDirectory, logicalResource.getPath() ).getParentFile(); + if ( request.getMethod().equals(HTTP_PUT_METHOD) && !destDir.exists() ) { destDir.mkdirs(); String relPath = PathUtil.getRelative( rootDirectory.getAbsolutePath(), destDir ); triggerAuditEvent( request.getRemoteAddr(), logicalResource.getPath(), relPath, AuditEvent.CREATE_DIR ); } - - File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() ); - + + File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource.getPath() ); + return new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), managedRepository.getRepository(), request.getRemoteAddr(), request.getDavSession(), locator, this, mimeTypes, auditListeners, consumers, archivaXworkUser ); @@ -721,9 +722,9 @@ public class ArchivaDavResourceFactory protected boolean isAuthorized( DavServletRequest request, String repositoryId ) throws DavException - { + { try - { + { AuthenticationResult result = httpAuth.getAuthenticationResult( request, null ); SecuritySession securitySession = httpAuth.getSecuritySession(); @@ -732,13 +733,15 @@ public class ArchivaDavResourceFactory WebdavMethodUtil.isWriteMethod( request.getMethod() ) ); } catch ( AuthenticationException e ) - { + { + boolean isPut = WebdavMethodUtil.isWriteMethod( request.getMethod() ); + // safety check for MRM-911 String guest = archivaXworkUser.getGuest(); try { if( servletAuth.isAuthorized( guest, - ( ( ArchivaDavResourceLocator ) request.getRequestLocator() ).getRepositoryId() ) ) + ( ( ArchivaDavResourceLocator ) request.getRequestLocator() ).getRepositoryId(), isPut ) ) { return true; } @@ -795,6 +798,8 @@ public class ArchivaDavResourceFactory if( allow ) { + boolean isPut = WebdavMethodUtil.isWriteMethod( request.getMethod() ); + for( String repository : repositories ) { // for prompted authentication @@ -817,7 +822,7 @@ public class ArchivaDavResourceFactory // for the current user logged in try { - if( servletAuth.isAuthorized( activePrincipal, repository ) ) + if( servletAuth.isAuthorized( activePrincipal, repository, isPut ) ) { getResource( locator, mergedRepositoryContents, logicalResource, repository ); } @@ -909,11 +914,12 @@ public class ArchivaDavResourceFactory } else { + boolean isPut = WebdavMethodUtil.isWriteMethod( request.getMethod() ); for( String repository : repositories ) { try - { - if( servletAuth.isAuthorized( activePrincipal, repository ) ) + { + if( servletAuth.isAuthorized( activePrincipal, repository, isPut ) ) { allow = true; break; @@ -974,4 +980,14 @@ public class ArchivaDavResourceFactory return true; } } + + public void setServletAuth( ServletAuthenticator servletAuth ) + { + this.servletAuth = servletAuth; + } + + public void setHttpAuth( HttpAuthenticator httpAuth ) + { + this.httpAuth = httpAuth; + } } diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProvider.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProvider.java index 2c5a39d35..1ebf02a93 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProvider.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProvider.java @@ -24,6 +24,7 @@ import org.apache.jackrabbit.webdav.WebdavRequest; import org.apache.jackrabbit.webdav.DavException; import org.apache.jackrabbit.webdav.DavServletRequest; import org.apache.maven.archiva.webdav.util.RepositoryPathUtil; +import org.apache.maven.archiva.webdav.util.WebdavMethodUtil; import org.apache.maven.archiva.security.ArchivaXworkUser; import org.apache.maven.archiva.security.ServletAuthenticator; import org.codehaus.plexus.redback.authentication.AuthenticationException; @@ -72,12 +73,14 @@ public class ArchivaDavSessionProvider } catch ( AuthenticationException e ) { + boolean isPut = WebdavMethodUtil.isWriteMethod( request.getMethod() ); + // safety check for MRM-911 String guest = archivaXworkUser.getGuest(); try { if( servletAuth.isAuthorized( guest, - ( ( ArchivaDavResourceLocator ) request.getRequestLocator() ).getRepositoryId() ) ) + ( ( ArchivaDavResourceLocator ) request.getRequestLocator() ).getRepositoryId(), isPut ) ) { request.setDavSession(new ArchivaDavSession()); return true; diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProviderTest.java b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProviderTest.java index e882c5ad6..1b7d82bda 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProviderTest.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/ArchivaDavSessionProviderTest.java @@ -362,7 +362,7 @@ public class ArchivaDavSessionProviderTest extends TestCase return true; } - public boolean isAuthorized(String arg0, String arg1) + public boolean isAuthorized(String arg0, String arg1, boolean isWriteRequest) throws UnauthorizedException { return true; diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.java b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.java index badd20cb6..e029ca583 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.java @@ -1,21 +1,550 @@ package org.apache.maven.archiva.webdav; -/** - * RepositoryServletSecurityTest +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import javax.servlet.http.HttpServletResponse; + +import net.sf.ehcache.CacheManager; + +import org.apache.commons.io.FileUtils; +import org.apache.jackrabbit.webdav.DavResourceFactory; +import org.apache.jackrabbit.webdav.DavSessionProvider; +import org.apache.maven.archiva.configuration.ArchivaConfiguration; +import org.apache.maven.archiva.configuration.Configuration; +import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; +import org.apache.maven.archiva.security.ArchivaXworkUser; +import org.apache.maven.archiva.security.ServletAuthenticator; +import org.codehaus.plexus.redback.authentication.AuthenticationException; +import org.codehaus.plexus.redback.authentication.AuthenticationResult; +import org.codehaus.plexus.redback.authorization.UnauthorizedException; +import org.codehaus.plexus.redback.system.DefaultSecuritySession; +import org.codehaus.plexus.redback.system.SecuritySession; +import org.codehaus.plexus.redback.xwork.filter.authentication.HttpAuthenticator; +import org.codehaus.plexus.redback.xwork.filter.authentication.basic.HttpBasicAuthentication; +import org.codehaus.plexus.spring.PlexusInSpringTestCase; +import org.easymock.MockControl; +import org.easymock.classextension.MockClassControl; +import org.easymock.internal.AlwaysMatcher; + +import com.meterware.httpunit.GetMethodWebRequest; +import com.meterware.httpunit.HttpUnitOptions; +import com.meterware.httpunit.PutMethodWebRequest; +import com.meterware.httpunit.WebRequest; +import com.meterware.httpunit.WebResponse; +import com.meterware.servletunit.InvocationContext; +import com.meterware.servletunit.ServletRunner; +import com.meterware.servletunit.ServletUnitClient; + +/** + * RepositoryServletSecurityTest + * + * Test the flow of the authentication and authorization checks. This does not necessarily + * perform redback security checking. + * * @author Joakim Erdfelt * @version $Id$ */ public class RepositoryServletSecurityTest - extends AbstractRepositoryServletTestCase + extends PlexusInSpringTestCase { - public void testSecuredGet() - { - - } + protected static final String REPOID_INTERNAL = "internal"; + + protected ServletUnitClient sc; + + protected File repoRootInternal; + + private ServletRunner sr; + + protected ArchivaConfiguration archivaConfiguration; + + private DavSessionProvider davSessionProvider; + + private MockControl servletAuthControl; + + private ServletAuthenticator servletAuth; + + private MockClassControl httpAuthControl; + + private HttpAuthenticator httpAuth; + + private ArchivaXworkUser archivaXworkUser; + + private RepositoryServlet servlet; - public void testSecuredBrowse() + public void setUp() + throws Exception { + super.setUp(); + + String appserverBase = getTestFile( "target/appserver-base" ).getAbsolutePath(); + System.setProperty( "appserver.base", appserverBase ); + + File testConf = getTestFile( "src/test/resources/repository-archiva.xml" ); + File testConfDest = new File( appserverBase, "conf/archiva.xml" ); + FileUtils.copyFile( testConf, testConfDest ); + + archivaConfiguration = (ArchivaConfiguration) lookup( ArchivaConfiguration.class ); + repoRootInternal = new File( appserverBase, "data/repositories/internal" ); + Configuration config = archivaConfiguration.getConfiguration(); + + config.addManagedRepository( createManagedRepository( REPOID_INTERNAL, "Internal Test Repo", repoRootInternal ) ); + saveConfiguration( archivaConfiguration ); + + CacheManager.getInstance().removeCache( "url-failures-cache" ); + + HttpUnitOptions.setExceptionsThrownOnErrorStatus( false ); + + sr = new ServletRunner( getTestFile( "src/test/resources/WEB-INF/repository-servlet-security-test/web.xml" ) ); + sr.registerServlet( "/repository/*", RepositoryServlet.class.getName() ); + sc = sr.newClient(); + + servletAuthControl = MockControl.createControl( ServletAuthenticator.class ); + servletAuthControl.setDefaultMatcher( MockControl.ALWAYS_MATCHER ); + servletAuth = (ServletAuthenticator) servletAuthControl.getMock(); + + httpAuthControl = + MockClassControl.createControl( HttpBasicAuthentication.class, HttpBasicAuthentication.class.getMethods() ); + httpAuthControl.setDefaultMatcher( MockControl.ALWAYS_MATCHER ); + httpAuth = (HttpAuthenticator) httpAuthControl.getMock(); + + archivaXworkUser = new ArchivaXworkUser(); + archivaXworkUser.setGuest( "guest" ); + + davSessionProvider = new ArchivaDavSessionProvider( servletAuth, httpAuth, archivaXworkUser ); + } + + protected ManagedRepositoryConfiguration createManagedRepository( String id, String name, File location ) + { + ManagedRepositoryConfiguration repo = new ManagedRepositoryConfiguration(); + repo.setId( id ); + repo.setName( name ); + repo.setLocation( location.getAbsolutePath() ); + return repo; + } + + protected void saveConfiguration() + throws Exception + { + saveConfiguration( archivaConfiguration ); + } + + protected void saveConfiguration( ArchivaConfiguration archivaConfiguration ) + throws Exception + { + archivaConfiguration.save( archivaConfiguration.getConfiguration() ); + } + + protected void setupCleanRepo( File repoRootDir ) + throws IOException + { + FileUtils.deleteDirectory( repoRootDir ); + if ( !repoRootDir.exists() ) + { + repoRootDir.mkdirs(); + } + } + + @Override + protected String getPlexusConfigLocation() + { + return "org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.xml"; + } + + @Override + protected void tearDown() + throws Exception + { + if ( sc != null ) + { + sc.clearContents(); + } + + if ( sr != null ) + { + sr.shutDown(); + } + + if ( repoRootInternal.exists() ) + { + FileUtils.deleteDirectory(repoRootInternal); + } + + servlet = null; + super.tearDown(); + } + + // test deploy with invalid user, and guest has no write access to repo + // 401 must be returned + public void testPutWithInvalidUserAndGuestHasNoWriteAccess() + throws Exception + { + setupCleanRepo( repoRootInternal ); + + String putUrl = "http://machine.com/repository/internal/path/to/artifact.jar"; + InputStream is = getClass().getResourceAsStream( "/artifact.jar" ); + assertNotNull( "artifact.jar inputstream", is ); + + WebRequest request = new PutMethodWebRequest( putUrl, is, "application/octet-stream" ); + InvocationContext ic = sc.newInvocation( request ); + servlet = (RepositoryServlet) ic.getServlet(); + servlet.setDavSessionProvider( davSessionProvider ); + + AuthenticationResult result = new AuthenticationResult(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + servletAuthControl.expectAndThrow( servletAuth.isAuthenticated( null, null ), + new AuthenticationException( "Authentication error" ) ); + + servletAuth.isAuthorized( "guest", "internal", true ); + servletAuthControl.setMatcher( MockControl.EQUALS_MATCHER ); + servletAuthControl.setThrowable( new UnauthorizedException( "'guest' has no write access to repository" ) ); + + httpAuthControl.replay(); + servletAuthControl.replay(); + + servlet.service( ic.getRequest(), ic.getResponse() ); + + httpAuthControl.verify(); + servletAuthControl.verify(); + + //assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getResponseCode()); + } + + // test deploy with invalid user, but guest has write access to repo + public void testPutWithInvalidUserAndGuestHasWriteAccess() + throws Exception + { + setupCleanRepo( repoRootInternal ); + + String putUrl = "http://machine.com/repository/internal/path/to/artifact.jar"; + InputStream is = getClass().getResourceAsStream( "/artifact.jar" ); + assertNotNull( "artifact.jar inputstream", is ); + + WebRequest request = new PutMethodWebRequest( putUrl, is, "application/octet-stream" ); + + InvocationContext ic = sc.newInvocation( request ); + servlet = (RepositoryServlet) ic.getServlet(); + servlet.setDavSessionProvider( davSessionProvider ); + + ArchivaDavResourceFactory archivaDavResourceFactory = (ArchivaDavResourceFactory) servlet.getResourceFactory(); + archivaDavResourceFactory.setHttpAuth( httpAuth ); + archivaDavResourceFactory.setServletAuth( servletAuth ); + + servlet.setResourceFactory( archivaDavResourceFactory ); + + AuthenticationResult result = new AuthenticationResult(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + servletAuthControl.expectAndThrow( servletAuth.isAuthenticated( null, null ), + new AuthenticationException( "Authentication error" ) ); + + servletAuth.isAuthorized( "guest", "internal", true ); + servletAuthControl.setMatcher( MockControl.EQUALS_MATCHER ); + servletAuthControl.setReturnValue( true ); + + // ArchivaDavResourceFactory#isAuthorized() + SecuritySession session = new DefaultSecuritySession(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + httpAuthControl.expectAndReturn( httpAuth.getSecuritySession(), session ); + servletAuthControl.expectAndThrow( servletAuth.isAuthenticated( null, result ), + new AuthenticationException( "Authentication error" ) ); + + // check if guest has write access + servletAuth.isAuthorized( "guest", "internal", true ); + servletAuthControl.setMatcher( MockControl.EQUALS_MATCHER ); + servletAuthControl.setReturnValue( true ); + + httpAuthControl.replay(); + servletAuthControl.replay(); + + servlet.service( ic.getRequest(), ic.getResponse() ); + + httpAuthControl.verify(); + servletAuthControl.verify(); + + // assertEquals( HttpServletResponse.SC_CREATED, response.getResponseCode() ); + } + + // test deploy with a valid user with no write access + public void testPutWithValidUserWithNoWriteAccess() + throws Exception + { + setupCleanRepo( repoRootInternal ); + + String putUrl = "http://machine.com/repository/internal/path/to/artifact.jar"; + InputStream is = getClass().getResourceAsStream( "/artifact.jar" ); + assertNotNull( "artifact.jar inputstream", is ); + + WebRequest request = new PutMethodWebRequest( putUrl, is, "application/octet-stream" ); + + InvocationContext ic = sc.newInvocation( request ); + servlet = (RepositoryServlet) ic.getServlet(); + servlet.setDavSessionProvider( davSessionProvider ); + + ArchivaDavResourceFactory archivaDavResourceFactory = (ArchivaDavResourceFactory) servlet.getResourceFactory(); + archivaDavResourceFactory.setHttpAuth( httpAuth ); + archivaDavResourceFactory.setServletAuth( servletAuth ); + servlet.setResourceFactory( archivaDavResourceFactory ); + + AuthenticationResult result = new AuthenticationResult(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, null ), true ); + + // ArchivaDavResourceFactory#isAuthorized() + SecuritySession session = new DefaultSecuritySession(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + httpAuthControl.expectAndReturn( httpAuth.getSecuritySession(), session ); + servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, result ), true ); + servletAuthControl.expectAndThrow( servletAuth.isAuthorized( null, session, "internal", true ), + new UnauthorizedException( "User not authorized" ) ); + + httpAuthControl.replay(); + servletAuthControl.replay(); + + servlet.service( ic.getRequest(), ic.getResponse() ); + + httpAuthControl.verify(); + servletAuthControl.verify(); + + // assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getResponseCode()); + } + + // test deploy with a valid user with write access + public void testPutWithValidUserWithWriteAccess() + throws Exception + { + setupCleanRepo( repoRootInternal ); + assertTrue( repoRootInternal.exists() ); + + String putUrl = "http://machine.com/repository/internal/path/to/artifact.jar"; + InputStream is = getClass().getResourceAsStream( "/artifact.jar" ); + assertNotNull( "artifact.jar inputstream", is ); + + WebRequest request = new PutMethodWebRequest( putUrl, is, "application/octet-stream" ); + + InvocationContext ic = sc.newInvocation( request ); + servlet = (RepositoryServlet) ic.getServlet(); + servlet.setDavSessionProvider( davSessionProvider ); + + ArchivaDavResourceFactory archivaDavResourceFactory = (ArchivaDavResourceFactory) servlet.getResourceFactory(); + archivaDavResourceFactory.setHttpAuth( httpAuth ); + archivaDavResourceFactory.setServletAuth( servletAuth ); + + servlet.setResourceFactory( archivaDavResourceFactory ); + + AuthenticationResult result = new AuthenticationResult(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, null ), true ); + + // ArchivaDavResourceFactory#isAuthorized() + SecuritySession session = new DefaultSecuritySession(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + httpAuthControl.expectAndReturn( httpAuth.getSecuritySession(), session ); + servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, result ), true ); + servletAuthControl.expectAndReturn( servletAuth.isAuthorized( null, session, "internal", true ), true ); + + httpAuthControl.replay(); + servletAuthControl.replay(); + + servlet.service( ic.getRequest(), ic.getResponse() ); + + httpAuthControl.verify(); + servletAuthControl.verify(); + + // assertEquals(HttpServletResponse.SC_CREATED, response.getResponseCode()); + } + + // test get with invalid user, and guest has read access to repo + public void testGetWithInvalidUserAndGuestHasReadAccess() + throws Exception + { + String commonsLangJar = "commons-lang/commons-lang/2.1/commons-lang-2.1.jar"; + String expectedArtifactContents = "dummy-commons-lang-artifact"; + + File artifactFile = new File( repoRootInternal, commonsLangJar ); + artifactFile.getParentFile().mkdirs(); + + FileUtils.writeStringToFile( artifactFile, expectedArtifactContents, null ); + + WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/internal/" + commonsLangJar ); + InvocationContext ic = sc.newInvocation( request ); + servlet = (RepositoryServlet) ic.getServlet(); + servlet.setDavSessionProvider( davSessionProvider ); + + ArchivaDavResourceFactory archivaDavResourceFactory = (ArchivaDavResourceFactory) servlet.getResourceFactory(); + archivaDavResourceFactory.setHttpAuth( httpAuth ); + archivaDavResourceFactory.setServletAuth( servletAuth ); + + servlet.setResourceFactory( archivaDavResourceFactory ); + + AuthenticationResult result = new AuthenticationResult(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + servletAuthControl.expectAndThrow( servletAuth.isAuthenticated( null, null ), + new AuthenticationException( "Authentication error" ) ); + servletAuthControl.expectAndReturn( servletAuth.isAuthorized( "guest", "internal", false ), true ); + + // ArchivaDavResourceFactory#isAuthorized() + SecuritySession session = new DefaultSecuritySession(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + httpAuthControl.expectAndReturn( httpAuth.getSecuritySession(), session ); + servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, result ), true ); + servletAuthControl.expectAndReturn( servletAuth.isAuthorized( null, session, "internal", true ), true ); + + httpAuthControl.replay(); + servletAuthControl.replay(); + + WebResponse response = sc.getResponse( request ); + + httpAuthControl.verify(); + servletAuthControl.verify(); + + assertEquals( HttpServletResponse.SC_OK, response.getResponseCode() ); + assertEquals( "Expected file contents", expectedArtifactContents, response.getText() ); + } + + // test get with invalid user, and guest has no read access to repo + public void testGetWithInvalidUserAndGuestHasNoReadAccess() + throws Exception + { + String commonsLangJar = "commons-lang/commons-lang/2.1/commons-lang-2.1.jar"; + String expectedArtifactContents = "dummy-commons-lang-artifact"; + + File artifactFile = new File( repoRootInternal, commonsLangJar ); + artifactFile.getParentFile().mkdirs(); + + FileUtils.writeStringToFile( artifactFile, expectedArtifactContents, null ); + + WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/internal/" + commonsLangJar ); + InvocationContext ic = sc.newInvocation( request ); + servlet = (RepositoryServlet) ic.getServlet(); + servlet.setDavSessionProvider( davSessionProvider ); + + AuthenticationResult result = new AuthenticationResult(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + servletAuthControl.expectAndThrow( servletAuth.isAuthenticated( null, null ), + new AuthenticationException( "Authentication error" ) ); + servletAuthControl.expectAndReturn( servletAuth.isAuthorized( "guest", "internal", false ), false ); + + httpAuthControl.replay(); + servletAuthControl.replay(); + + WebResponse response = sc.getResponse( request ); + + httpAuthControl.verify(); + servletAuthControl.verify(); + + assertEquals( HttpServletResponse.SC_UNAUTHORIZED, response.getResponseCode() ); + } + + // test get with valid user with read access to repo + public void testGetWithAValidUserWithReadAccess() + throws Exception + { + String commonsLangJar = "commons-lang/commons-lang/2.1/commons-lang-2.1.jar"; + String expectedArtifactContents = "dummy-commons-lang-artifact"; + + File artifactFile = new File( repoRootInternal, commonsLangJar ); + artifactFile.getParentFile().mkdirs(); + + FileUtils.writeStringToFile( artifactFile, expectedArtifactContents, null ); + + WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/internal/" + commonsLangJar ); + InvocationContext ic = sc.newInvocation( request ); + servlet = (RepositoryServlet) ic.getServlet(); + servlet.setDavSessionProvider( davSessionProvider ); + + ArchivaDavResourceFactory archivaDavResourceFactory = (ArchivaDavResourceFactory) servlet.getResourceFactory(); + archivaDavResourceFactory.setHttpAuth( httpAuth ); + archivaDavResourceFactory.setServletAuth( servletAuth ); + + servlet.setResourceFactory( archivaDavResourceFactory ); + + AuthenticationResult result = new AuthenticationResult(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, null ), true ); + + // ArchivaDavResourceFactory#isAuthorized() + SecuritySession session = new DefaultSecuritySession(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + httpAuthControl.expectAndReturn( httpAuth.getSecuritySession(), session ); + servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, result ), true ); + servletAuthControl.expectAndReturn( servletAuth.isAuthorized( null, session, "internal", true ), true ); + + httpAuthControl.replay(); + servletAuthControl.replay(); + + WebResponse response = sc.getResponse( request ); + + httpAuthControl.verify(); + servletAuthControl.verify(); + + assertEquals( HttpServletResponse.SC_OK, response.getResponseCode() ); + assertEquals( "Expected file contents", expectedArtifactContents, response.getText() ); + } + + // test get with valid user with no read access to repo + public void testGetWithAValidUserWithNoReadAccess() + throws Exception + { + String commonsLangJar = "commons-lang/commons-lang/2.1/commons-lang-2.1.jar"; + String expectedArtifactContents = "dummy-commons-lang-artifact"; + + File artifactFile = new File( repoRootInternal, commonsLangJar ); + artifactFile.getParentFile().mkdirs(); + + FileUtils.writeStringToFile( artifactFile, expectedArtifactContents, null ); + + WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/internal/" + commonsLangJar ); + InvocationContext ic = sc.newInvocation( request ); + servlet = (RepositoryServlet) ic.getServlet(); + servlet.setDavSessionProvider( davSessionProvider ); + + ArchivaDavResourceFactory archivaDavResourceFactory = (ArchivaDavResourceFactory) servlet.getResourceFactory(); + archivaDavResourceFactory.setHttpAuth( httpAuth ); + archivaDavResourceFactory.setServletAuth( servletAuth ); + + servlet.setResourceFactory( archivaDavResourceFactory ); + + AuthenticationResult result = new AuthenticationResult(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, null ), true ); + + // ArchivaDavResourceFactory#isAuthorized() + SecuritySession session = new DefaultSecuritySession(); + httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); + httpAuthControl.expectAndReturn( httpAuth.getSecuritySession(), session ); + servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, result ), true ); + servletAuthControl.expectAndThrow( servletAuth.isAuthorized( null, session, "internal", true ), + new UnauthorizedException( "User not authorized to read repository." ) ); + + httpAuthControl.replay(); + servletAuthControl.replay(); + + WebResponse response = sc.getResponse( request ); + + httpAuthControl.verify(); + servletAuthControl.verify(); + + assertEquals( HttpServletResponse.SC_UNAUTHORIZED, response.getResponseCode() ); } } diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/resources/WEB-INF/repository-servlet-security-test/web.xml b/archiva-modules/archiva-web/archiva-webdav/src/test/resources/WEB-INF/repository-servlet-security-test/web.xml new file mode 100644 index 000000000..291aa01ec --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/resources/WEB-INF/repository-servlet-security-test/web.xml @@ -0,0 +1,45 @@ + + + + + + Apache Archiva + + + org.springframework.web.context.ContextLoaderListener + + + + contextClass + org.codehaus.plexus.spring.PlexusWebApplicationContext + + + + contextConfigLocation + + classpath*:/META-INF/plexus/components.xml + classpath*:/META-INF/spring-context.xml + target/test-classes/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.xml + + + + diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.xml b/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.xml index d7087095a..53e79073f 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.xml +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.xml @@ -68,9 +68,12 @@ default org.apache.maven.archiva.webdav.DefaultDavServerManager DefaultDavServerManager - - proxied - + + + org.apache.maven.archiva.webdav.DavServerComponent + proxied + + @@ -99,174 +102,74 @@ org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers default - org.apache.maven.archiva.web.repository.StubRepositoryContentConsumers + org.apache.maven.archiva.webdav.StubRepositoryContentConsumers - - + org.codehaus.plexus.redback.system.SecuritySystem default org.codehaus.plexus.redback.system.DefaultSecuritySystem - - - org.codehaus.plexus.redback.authentication.AuthenticationManager - authnManager - - - org.codehaus.plexus.redback.authorization.Authorizer - rbac - authorizer - - - org.codehaus.plexus.redback.users.UserManager - memory - userManager - - - org.codehaus.plexus.redback.keys.KeyManager - memory - keyManager - - - org.codehaus.plexus.redback.policy.UserSecurityPolicy - policy - - - - - org.codehaus.plexus.redback.authentication.Authenticator - user-manager - org.codehaus.plexus.redback.authentication.users.UserManagerAuthenticator + + + org.apache.maven.archiva.webdav.ArchivaDavResourceFactory + org.apache.maven.archiva.webdav.ArchivaDavResourceFactory - org.codehaus.plexus.redback.users.UserManager - memory - userManager + org.apache.maven.archiva.configuration.ArchivaConfiguration + archivaConfiguration - org.codehaus.plexus.redback.policy.UserSecurityPolicy - securityPolicy - - - - - - org.codehaus.plexus.redback.authentication.Authenticator - keystore - org.codehaus.plexus.redback.authentication.keystore.KeyStoreAuthenticator - + org.apache.maven.archiva.repository.RepositoryContentFactory + repositoryFactory + - org.codehaus.plexus.redback.keys.KeyManager - memory - keystore + org.apache.maven.archiva.repository.content.RepositoryRequest + repositoryRequest - org.codehaus.plexus.redback.users.UserManager - memory - userManager - - - - - - org.codehaus.plexus.redback.authorization.rbac.evaluator.PermissionEvaluator - default - org.codehaus.plexus.redback.authorization.rbac.evaluator.DefaultPermissionEvaluator - - - - org.codehaus.plexus.redback.users.UserManager - memory - userManager - - - - - - org.codehaus.plexus.redback.authorization.Authorizer - rbac - org.codehaus.plexus.redback.authorization.rbac.RbacAuthorizer - - - org.codehaus.plexus.redback.rbac.RBACManager - memory - manager + org.apache.maven.archiva.proxy.RepositoryProxyConnectors + connectors - org.codehaus.plexus.redback.users.UserManager - memory - userManager + org.apache.maven.archiva.repository.metadata.MetadataTools + metadataTools - org.codehaus.plexus.redback.authorization.rbac.evaluator.PermissionEvaluator + org.apache.maven.archiva.security.ServletAuthenticator + servletAuth + + + org.apache.maven.archiva.webdav.util.MimeTypes + mimeTypes + + + org.codehaus.plexus.redback.xwork.filter.authentication.HttpAuthenticator + basic + httpAuth + + + org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers default - evaluator - - - - - - org.codehaus.plexus.redback.role.RoleManager - default - org.codehaus.plexus.redback.role.DefaultRoleManager - singleton - - - org.codehaus.plexus.redback.role.merger.RoleModelMerger - default - modelMerger - org.codehaus.plexus.redback.role.validator.RoleModelValidator - default - modelValidator + org.codehaus.plexus.digest.ChecksumFile + checksum - org.codehaus.plexus.redback.role.processor.RoleModelProcessor - default - modelProcessor + org.codehaus.plexus.digest.Digester + sha1 + digestSha1 - org.codehaus.plexus.redback.role.template.RoleTemplateProcessor - default - templateProcessor + org.codehaus.plexus.digest.Digester + md5 + digestMd5 - org.codehaus.plexus.redback.rbac.RBACManager - memory - rbacManager - - - org.codehaus.plexus.PlexusContainer - container - - - - - - org.codehaus.plexus.redback.role.processor.RoleModelProcessor - default - org.codehaus.plexus.redback.role.processor.DefaultRoleModelProcessor - - - org.codehaus.plexus.redback.rbac.RBACManager - memory - rbacManager - - - - - - org.codehaus.plexus.redback.role.template.RoleTemplateProcessor - default - org.codehaus.plexus.redback.role.template.DefaultRoleTemplateProcessor - - - org.codehaus.plexus.redback.rbac.RBACManager - memory - rbacManager - + org.apache.maven.archiva.security.ArchivaXworkUser + archivaXworkUser + diff --git a/pom.xml b/pom.xml index 7d311138b..bdffb05b2 100644 --- a/pom.xml +++ b/pom.xml @@ -204,6 +204,12 @@ 1.2_Java1.3 test + + easymock + easymockclassextension + 1.2 + test + org.slf4j jcl104-over-slf4j