]> source.dussan.org Git - archiva.git/commitdiff
[MRM-1468] Fix XSS vulnerability in Archiva
authorMaria Odea B. Ching <oching@apache.org>
Tue, 3 May 2011 02:54:19 +0000 (02:54 +0000)
committerMaria Odea B. Ching <oching@apache.org>
Tue, 3 May 2011 02:54:19 +0000 (02:54 +0000)
submitted by Marc Jansen Tan Chua

o tightened up validation on input/edit forms + unit tests
o added selenium tests for XSS vunerabilities
o used c:out in some of the pages so output will be escaped if containing html characters

git-svn-id: https://svn.apache.org/repos/asf/archiva/branches/archiva-1.3.x@1098897 13f79535-47bb-0310-9956-ffa450edef68

44 files changed:
archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/AppearanceTest.java
archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/ArtifactManagementTest.java
archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/LegacySupportTest.java
archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/NetworkProxiesTest.java
archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/RepositoryTest.java
archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/XSSSecurityTest.java [new file with mode: 0644]
archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/parent/AbstractArchivaTest.java
archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/parent/AbstractArtifactManagementTest.java
archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/parent/AbstractRepositoryTest.java
archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/parent/AbstractSeleniumTest.java
archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/DeleteArtifactAction.java
archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/admin/appearance/EditOrganisationInfoAction.java
archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/admin/legacy/AddLegacyArtifactPathAction.java
archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/admin/networkproxies/ConfigureNetworkProxyAction.java
archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/admin/repositories/AddManagedRepositoryAction.java
archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/admin/repositories/EditManagedRepositoryAction.java
archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/DeleteArtifactAction-validation.xml
archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/admin/appearance/EditOrganisationInfoAction-validation.xml
archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/admin/legacy/AddLegacyArtifactPathAction-validation.xml
archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/admin/networkproxies/ConfigureNetworkProxyAction-saveNetworkProxy-validation.xml
archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/admin/repositories/AddManagedRepositoryAction-validation.xml
archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/admin/repositories/EditManagedRepositoryAction-validation.xml
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addLegacyArtifactPath.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addRepository.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/appearance.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/confirmAddRepository.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteNetworkProxy.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteRepository.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editAppearance.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editNetworkProxy.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editRepository.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/legacyArtifactPath.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/networkProxies.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/repositories.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/components/companyLogo.jsp
archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/deleteArtifact.jsp
archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/DeleteArtifactActionTest.java [new file with mode: 0644]
archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/appearance/EditOrganizationInfoActionTest.java
archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/legacy/AddLegacyArtifactPathActionTest.java [new file with mode: 0644]
archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/networkproxies/ConfigureNetworkProxyActionTest.java [new file with mode: 0644]
archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/AbstractManagedRepositoryActionTest.java [new file with mode: 0644]
archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/AddManagedRepositoryActionTest.java
archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/EditManagedRepositoryActionTest.java
archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/validator/utils/ValidatorUtil.java [new file with mode: 0644]

index 94f8b700d3c145578a71d98be133a43a8ad4a919..dbd140ab2617db908fd5194ea31a025b1eca93f8 100644 (file)
@@ -25,15 +25,47 @@ import org.testng.annotations.Test;
 @Test( groups = { "appearance" }, dependsOnMethods = { "testWithCorrectUsernamePassword" }, sequential = true )
 public class AppearanceTest extends AbstractArchivaTest
 {
-       public void testAddAppearanceNullValues()
+       public void testAddAppearanceEmptyValues()
        {
                goToAppearancePage();
                clickLinkWithText( "Edit" );
                addEditAppearance( "", "", "" );
                assertTextPresent( "You must enter a name" );
        }
-       
-       @Test( dependsOnMethods = { "testAddAppearanceNullValues" })
+
+        @Test( dependsOnMethods = { "testAddAppearanceEmptyValues" })
+       public void testAddAppearanceInvalidValues()
+       {
+               addEditAppearance( "<>~+[ ]'\"" , "/home/user/abcXYZ0129._/\\~:?!&=-<> ~+[ ]'\"" , "/home/user/abcXYZ0129._/\\~:?!&=-<> ~+[ ]'\"" );
+               assertTextPresent( "Organisation name must only contain alphanumeric characters, white-spaces(' '), equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+                assertTextPresent( "You must enter a URL" );
+                assertXpathCount("//span[@class='errorMessage' and text()='You must enter a URL']", 2);
+        }
+
+        @Test( dependsOnMethods = { "testAddAppearanceInvalidValues" })
+       public void testAddAppearanceInvalidOrganisationName()
+       {
+               addEditAppearance( "<>~+[ ]'\"" , "http://www.apache.org/" , "http://www.apache.org/images/asf_logo_wide.gifs" );
+                assertTextPresent( "Organisation name must only contain alphanumeric characters, white-spaces(' '), equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+       }
+
+        @Test( dependsOnMethods = { "testAddAppearanceInvalidOrganisationName" })
+       public void testAddAppearanceInvalidOrganisationUrl()
+       {
+               addEditAppearance( "The Apache Software Foundation" , "/home/user/abcXYZ0129._/\\~:?!&=-<> ~+[ ]'\"" , "http://www.apache.org/images/asf_logo_wide.gifs" );
+               assertTextPresent( "You must enter a URL" );
+                assertXpathCount("//span[@class='errorMessage' and text()='You must enter a URL']", 1);
+        }
+
+        @Test( dependsOnMethods = { "testAddAppearanceInvalidOrganisationUrl" })
+       public void testAddAppearanceInvalidOrganisationLogo()
+       {
+               addEditAppearance( "The Apache Software Foundation" , "http://www.apache.org/" , "/home/user/abcXYZ0129._/\\~:?!&=-<> ~+[ ]'\"" );
+               assertTextPresent( "You must enter a URL" );
+                assertXpathCount("//span[@class='errorMessage' and text()='You must enter a URL']", 1);
+        }
+
+       @Test( dependsOnMethods = { "testAddAppearanceInvalidOrganisationLogo" })
        public void testAddAppearanceValidValues()
        {
                addEditAppearance( "The Apache Software Foundation" , "http://www.apache.org/" , "http://www.apache.org/images/asf_logo_wide.gifs" );
@@ -46,6 +78,6 @@ public class AppearanceTest extends AbstractArchivaTest
                clickLinkWithText( "Edit" );
                addEditAppearance( "Apache Software Foundation" , "http://www.apache.org/" , "http://www.apache.org/images/asf_logo_wide.gifs" );
                assertTextPresent( "Apache Software Foundation" );
-       }
-       
+        }
+
 }
\ No newline at end of file
index 4eb22b172d9e1cdf81d270af9359a4c2ede66772..d3f2836c3bc854b177b2e0ec950e9826398fabe8 100644 (file)
@@ -82,7 +82,7 @@ public class ArtifactManagementTest
                addArtifact( getGroupId() , getArtifactId(), getVersion(), getPackaging() , " ", getRepositoryId() );
                assertTextPresent( "Please add a file to upload." );
        }
-       
+        
     @Test(groups = "requiresUpload")
        public void testAddArtifactValidValues()
        {
@@ -139,4 +139,25 @@ public class ArtifactManagementTest
                deleteArtifact( "delete", "delete", "asdf", "internal");
                assertTextPresent( "Invalid version." );
        }
+
+        // HTML select should have the proper value, else it will cause a selenium error: Option with label 'customValue' not found
+        public void testDeleteArtifactInvalidValues()
+       {
+               deleteArtifact( "<> \\/~+[ ]'\"", "<> \\/~+[ ]'\"", "<>", "internal");
+               assertTextPresent( "Invalid version." );
+                assertTextPresent( "Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+                assertTextPresent( "Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
+
+        public void testDeleteArtifactInvalidGroupId()
+       {
+               deleteArtifact( "<> \\/~+[ ]'\"", "delete", "1.0", "internal");
+               assertTextPresent( "Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
+
+        public void testDeleteArtifactInvalidArtifactId()
+       {
+               deleteArtifact( "delete", "<> \\/~+[ ]'\"", "1.0", "internal");
+               assertTextPresent( "Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
 }
index 26212a949501e9dcdaa274f0d73f47a6c61b3128..183c15f466e99ce9c4359e444ae3632e2e6746bb 100644 (file)
@@ -72,4 +72,58 @@ public class LegacySupportTest
                addLegacyArtifactPath( "test" , "test" , "test" , "1.0-SNAPSHOT" , "testing" , "");
                assertTextPresent( "You must enter a type." );
        }
+
+        @Test( dependsOnMethods = { "testAddLegacyArtifact_NullType" })
+       public void testAddLegacyArtifact_InvalidValues()
+       {
+               addLegacyArtifactPath( "<> ~+[ ]'\"" , "<> \\/~+[ ]'\"" , "<> \\/~+[ ]'\"" , "<> \\/~+[ ]'\"" , "<> \\/~+[ ]'\"" , "<> \\/~+[ ]'\"");
+               assertTextPresent( "Legacy path must only contain alphanumeric characters, forward-slashes(/), back-slashes(\\), underscores(_), dots(.), and dashes(-)." );
+                assertTextPresent( "Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+                assertTextPresent( "Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+                assertTextPresent( "Version must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+                assertTextPresent( "Classifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+                assertTextPresent( "Type must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
+
+        @Test( dependsOnMethods = { "testAddLegacyArtifact_InvalidValues" })
+       public void testAddLegacyArtifact_InvalidLegacyPath()
+       {
+               addLegacyArtifactPath( "<> ~+[ ]'\"" , "test" , "test" , "1.0-SNAPSHOT" , "testing" , "jar");
+               assertTextPresent( "Legacy path must only contain alphanumeric characters, forward-slashes(/), back-slashes(\\), underscores(_), dots(.), and dashes(-)." );
+       }
+
+        @Test( dependsOnMethods = { "testAddLegacyArtifact_InvalidLegacyPath" })
+       public void testAddLegacyArtifact_InvalidGroupId()
+       {
+               addLegacyArtifactPath( "test" , "<> \\/~+[ ]'\"" , "test" , "1.0-SNAPSHOT" , "testing" , "jar");
+               assertTextPresent( "Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
+
+        @Test( dependsOnMethods = { "testAddLegacyArtifact_InvalidGroupId" })
+       public void testAddLegacyArtifact_InvalidArtifactId()
+       {
+               addLegacyArtifactPath( "test" , "test" , "<> \\/~+[ ]'\"" , "1.0-SNAPSHOT" , "testing" , "jar");
+               assertTextPresent( "Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
+
+        @Test( dependsOnMethods = { "testAddLegacyArtifact_InvalidArtifactId" })
+       public void testAddLegacyArtifact_InvalidVersion()
+       {
+               addLegacyArtifactPath( "test" , "test" , "test" , "<> \\/~+[ ]'\"" , "testing" , "jar");
+               assertTextPresent( "Version must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
+
+        @Test( dependsOnMethods = { "testAddLegacyArtifact_InvalidVersion" })
+       public void testAddLegacyArtifact_InvalidType()
+       {
+               addLegacyArtifactPath( "test" , "test" , "test" , "1.0-SNAPSHOT" , "testing" , "<> \\/~+[ ]'\"");
+               assertTextPresent( "Type must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
+
+        @Test( dependsOnMethods = { "testAddLegacyArtifact_InvalidType" })
+       public void testAddLegacyArtifact_InvalidClassifier()
+       {
+               addLegacyArtifactPath( "test" , "test" , "test" , "1.0-SNAPSHOT" , "<> \\/~+[ ]'\"" , "jar");
+               assertTextPresent( "Classifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
 }
index b12a096b8400c83dc820dbe40dc0de6317ff4cd0..8224353d233356e32012f5006fd39ce0782a65aa 100644 (file)
@@ -59,8 +59,60 @@ public class NetworkProxiesTest
                addNetworkProxy( "testing123", "http", "", "8080", "", "");
                assertTextPresent( "You must enter a host." );
        }
-       
+
        @Test (dependsOnMethods = { "testAddNetworkProxiesNullHostname" } )
+       public void testAddNetworkProxiesInvalidValues()
+       {
+               goToNetworkProxiesPage();
+               addNetworkProxy( "<> \\/~+[ ]'\"", "<> ~+[ ]'\"", "<> ~+[ ]'\"", "0", "<> ~+[ ]'\"", "");
+               assertTextPresent( "Proxy id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+                assertTextPresent( "Protocol must only contain alphanumeric characters, forward-slashes(/), back-slashes(\\), dots(.), colons(:), and dashes(-)." );
+                assertTextPresent( "Host must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+                assertTextPresent( "Port needs to be larger than 1" );
+                assertTextPresent( "Username must only contain alphanumeric characters, at's(@), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), and dashes(-)." );
+       }
+
+        @Test (dependsOnMethods = { "testAddNetworkProxiesInvalidValues" } )
+       public void testAddNetworkProxiesInvalidIdentifier()
+       {
+               goToNetworkProxiesPage();
+               addNetworkProxy( "<> \\/~+[ ]'\"", "http", "localhost", "8080", "", "");
+               assertTextPresent( "Proxy id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
+
+        @Test (dependsOnMethods = { "testAddNetworkProxiesInvalidIdentifier" } )
+       public void testAddNetworkProxiesInvalidProtocol()
+       {
+               goToNetworkProxiesPage();
+               addNetworkProxy( "testing123", "<> ~+[ ]'\"", "localhost", "8080", "", "");
+               assertTextPresent( "Protocol must only contain alphanumeric characters, forward-slashes(/), back-slashes(\\), dots(.), colons(:), and dashes(-)." );
+       }
+
+        @Test (dependsOnMethods = { "testAddNetworkProxiesInvalidProtocol" } )
+       public void testAddNetworkProxiesInvalidHostname()
+       {
+               goToNetworkProxiesPage();
+               addNetworkProxy( "testing123", "http", "<> ~+[ ]'\"", "8080", "", "");
+               assertTextPresent( "Host must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+       }
+
+        @Test (dependsOnMethods = { "testAddNetworkProxiesInvalidHostname" } )
+       public void testAddNetworkProxiesInvalidPort()
+       {
+               goToNetworkProxiesPage();
+               addNetworkProxy( "testing123", "http", "localhost", "0", "", "");
+               assertTextPresent( "Port needs to be larger than 1" );
+       }
+
+        @Test (dependsOnMethods = { "testAddNetworkProxiesInvalidPort" } )
+       public void testAddNetworkProxiesInvalidUsername()
+       {
+               goToNetworkProxiesPage();
+               addNetworkProxy( "testing123", "http", "localhost", "8080", "<> ~+[ ]'\"", "");
+               assertTextPresent( "Username must only contain alphanumeric characters, at's(@), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), and dashes(-)." );
+        }
+
+        @Test (dependsOnMethods = { "testAddNetworkProxiesInvalidUsername" } )
        public void testAddNetworkProxiesValidValues()
        {
                goToNetworkProxiesPage();
@@ -68,7 +120,7 @@ public class NetworkProxiesTest
                assertPage( "Apache Archiva \\ Administration - Network Proxies" );
                assertTextPresent( "testing123" );
        }
-       
+
        @Test (dependsOnMethods = { "testAddNetworkProxiesValidValues" } )
        public void testEditNetworkProxy()
        {
@@ -92,5 +144,5 @@ public class NetworkProxiesTest
                assertPage( "Apache Archiva \\ Administration - Network Proxies" );
                assertTextPresent( "testing123" );
        }
-       
+
 }
index 0c7df55d1a7962c02db9d2ddce7e2430800f0b9a..8b7743253522c52852d7dbb5a6da08b8fdad71f4 100644 (file)
@@ -35,9 +35,66 @@ public class RepositoryTest
                assertTextPresent( "Managed Repository Sample 1" );             
                assertRepositoriesPage();
        }
-       
-        @Test(dependsOnMethods = { "testAddManagedRepoValidValues" } )
-       public void testAddManagedRepoInvalidValues()
+
+        @Test(dependsOnMethods = { "testAddManagedRepoValidValues" } )
+        public void testAddManagedRepoInvalidValues()
+        {
+                goToRepositoriesPage();
+               getSelenium().open( "/archiva/admin/addRepository.action" );    ;
+               addManagedRepository( "<> \\/~+[ ]'\"", "<>\\~+[]'\"" , "<> ~+[ ]'\"" , "<> ~+[ ]'\"", "Maven 2.x Repository", "", "-1", "101" );
+               assertTextPresent( "Identifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+               assertTextPresent( "Directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+               assertTextPresent( "Repository Name must only contain alphanumeric characters, white-spaces(' '), forward-slashes(/), open-parenthesis('('), close-parenthesis(')'), underscores(_), dots(.), and dashes(-)." );
+                assertTextPresent( "Index directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+                assertTextPresent( "Repository Purge By Retention Count needs to be between 1 and 100.");
+                assertTextPresent( "Repository Purge By Days Older Than needs to be larger than 0.");
+               assertTextPresent( "Invalid cron expression." );
+        }
+
+        @Test(dependsOnMethods = { "testAddManagedRepoInvalidValues" } )
+       public void testAddManagedRepoInvalidIdentifier()
+       {
+               addManagedRepository( "<> \\/~+[ ]'\"", "name" , "/home" , "/.index", "Maven 2.x Repository", "0 0 * * * ?", "1", "1" );
+               assertTextPresent( "Identifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       }
+
+       @Test(dependsOnMethods = { "testAddManagedRepoInvalidIdentifier" } )
+       public void testAddManagedRepoInvalidRepoName()
+       {
+               addManagedRepository( "identifier", "<>\\~+[]'\"" , "/home" , "/.index", "Maven 2.x Repository", "0 0 * * * ?", "1", "1" );
+               assertTextPresent( "Repository Name must only contain alphanumeric characters, white-spaces(' '), forward-slashes(/), open-parenthesis('('), close-parenthesis(')'), underscores(_), dots(.), and dashes(-)." );
+       }
+
+       @Test(dependsOnMethods = { "testAddManagedRepoInvalidRepoName" } )
+       public void testAddManagedRepoInvalidDirectory()
+       {
+               addManagedRepository( "identifier", "name" , "<> ~+[ ]'\"" , "/.index", "Maven 2.x Repository", "0 0 * * * ?", "1", "1" );
+               assertTextPresent( "Directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+       }
+
+       @Test(dependsOnMethods = { "testAddManagedRepoInvalidDirectory" } )
+       public void testAddManagedRepoInvalidIndexDir()
+       {
+               addManagedRepository( "identifier", "name" , "/home" , "<> ~+[ ]'\"", "Maven 2.x Repository", "0 0 * * * ?", "1", "1" );
+               assertTextPresent( "Index directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+       }
+
+        @Test(dependsOnMethods = { "testAddManagedRepoInvalidIndexDir" } )
+       public void testAddManagedRepoInvalidRetentionCount()
+       {
+               addManagedRepository( "identifier", "name" , "/home" , "/.index", "Maven 2.x Repository", "0 0 * * * ?", "1", "101" );
+               assertTextPresent( "Repository Purge By Retention Count needs to be between 1 and 100." );
+       }
+
+        @Test(dependsOnMethods = { "testAddManagedRepoInvalidRetentionCount" } )
+       public void testAddManagedRepoInvalidDaysOlder()
+       {
+               addManagedRepository( "identifier", "name" , "/home" , "/.index", "Maven 2.x Repository", "0 0 * * * ?", "-1", "1" );
+               assertTextPresent( "Repository Purge By Days Older Than needs to be larger than 0." );
+       }
+
+       @Test(dependsOnMethods = { "testAddManagedRepoInvalidDaysOlder" } )
+       public void testAddManagedRepoBlankValues()
        {                               
                goToRepositoriesPage();
                getSelenium().open( "/archiva/admin/addRepository.action" );    ;       
@@ -48,7 +105,7 @@ public class RepositoryTest
                assertTextPresent( "Invalid cron expression." );
        }
        
-       @Test(dependsOnMethods = { "testAddManagedRepoInvalidValues" } )
+       @Test(dependsOnMethods = { "testAddManagedRepoBlankValues" } )
        public void testAddManagedRepoNoIdentifier()
        {               
                addManagedRepository( "", "name" , "/home" , "/.index", "Maven 2.x Repository", "0 0 * * * ?", "", "" );
@@ -86,8 +143,62 @@ public class RepositoryTest
                assertTextPresent( "Managed Repository Sample" );
        }
 
+        @Test(dependsOnMethods = { "testAddManagedRepoForEdit" } )
+        public void testEditManagedRepoInvalidValues()
+       {
+               editManagedRepository("<>\\~+[]'\"" , "<> ~+[ ]'\"" , "<> ~+[ ]'\"", "Maven 2.x Repository", "", "-1", "101");
+                assertTextPresent( "Directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+               assertTextPresent( "Repository Name must only contain alphanumeric characters, white-spaces(' '), forward-slashes(/), open-parenthesis('('), close-parenthesis(')'), underscores(_), dots(.), and dashes(-)." );
+                assertTextPresent( "Index directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+                assertTextPresent( "Repository Purge By Retention Count needs to be between 1 and 100.");
+                assertTextPresent( "Repository Purge By Days Older Than needs to be larger than 0.");
+               assertTextPresent( "Invalid cron expression." );
+       }
+
+        @Test(dependsOnMethods = { "testEditManagedRepoInvalidValues" } )
+        public void testEditManagedRepoInvalidRepoName()
+       {
+                editManagedRepository("<>\\~+[]'\"" , "/home" , "/.index", "Maven 2.x Repository", "0 0 * * * ?", "1", "1");
+                assertTextPresent( "Repository Name must only contain alphanumeric characters, white-spaces(' '), forward-slashes(/), open-parenthesis('('), close-parenthesis(')'), underscores(_), dots(.), and dashes(-)." );
+       }
+
+        @Test(dependsOnMethods = { "testEditManagedRepoInvalidRepoName" } )
+        public void testEditManagedRepoInvalidDirectory()
+       {
+                editManagedRepository("name" , "<> ~+[ ]'\"" , "/.index", "Maven 2.x Repository", "0 0 * * * ?", "1", "1");
+                assertTextPresent( "Directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+       }
+
+        @Test(dependsOnMethods = { "testEditManagedRepoInvalidDirectory" } )
+        public void testEditManagedRepoInvalidIndexDir()
+       {
+                editManagedRepository("name" , "/home" , "<> ~+[ ]'\"", "Maven 2.x Repository", "0 0 * * * ?", "1", "1");
+                assertTextPresent( "Index directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+       }
+
+        @Test(dependsOnMethods = { "testEditManagedRepoInvalidIndexDir" } )
+        public void testEditManagedRepoInvalidCron()
+       {
+                editManagedRepository("name" , "/home" , "/.index", "Maven 2.x Repository", "", "1", "1");
+                assertTextPresent( "Invalid cron expression." );
+       }
+
+        @Test(dependsOnMethods = { "testEditManagedRepoInvalidCron" } )
+        public void testEditManagedRepoInvalidRetentionCount()
+       {
+                editManagedRepository("name" , "/home" , "/.index", "Maven 2.x Repository", "0 0 * * * ?", "1", "101");
+                assertTextPresent( "Repository Purge By Retention Count needs to be between 1 and 100." );
+       }
+
+        @Test(dependsOnMethods = { "testEditManagedRepoInvalidRetentionCount" } )
+        public void testEditManagedRepoInvalidDaysOlder()
+       {
+                editManagedRepository("name" , "/home" , "/.index", "Maven 2.x Repository", "0 0 * * * ?", "-1", "1");
+                assertTextPresent( "Repository Purge By Days Older Than needs to be larger than 0." );
+       }
+
        //TODO
-       @Test(dependsOnMethods = { "testAddManagedRepoForEdit" } )
+       @Test(dependsOnMethods = { "testEditManagedRepoInvalidDaysOlder" } )
        public void testEditManagedRepo()
        {
                editManagedRepository( "repository.name" , "Managed Repo" );
@@ -140,11 +251,11 @@ public class RepositoryTest
                addRemoteRepository( "remoterepo" , "Remote Repository Sample" , "http://repository.codehaus.org/org/codehaus/mojo/" , "" , "" , "" , "Maven 2.x Repository" );
                assertTextPresent( "Remote Repository Sample" );
        }
-    \r
+    
     // *** BUNDLED REPOSITORY TEST ***
-    \r
-    @Test ( dependsOnMethods = { "testWithCorrectUsernamePassword" }, alwaysRun = true )\r
-    public void testBundledRepository()\r
+    
+    @Test ( dependsOnMethods = { "testWithCorrectUsernamePassword" }, alwaysRun = true )
+    public void testBundledRepository()
     {
         String repo1 = baseUrl + "repository/internal/";
         String repo2 = baseUrl + "repository/snapshots/";
@@ -152,7 +263,7 @@ public class RepositoryTest
         assertRepositoryAccess( repo1 );
         assertRepositoryAccess( repo2 );
         
-        getSelenium().open( "/archiva" );\r
+        getSelenium().open( "/archiva" );
     }
     
     private void assertRepositoryAccess( String repo )
diff --git a/archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/XSSSecurityTest.java b/archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/XSSSecurityTest.java
new file mode 100644 (file)
index 0000000..1b9cfa1
--- /dev/null
@@ -0,0 +1,190 @@
+package org.apache.archiva.web.test;
+
+/*
+ * 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 org.testng.annotations.Test;
+import org.apache.archiva.web.test.parent.AbstractArchivaTest;
+
+/**
+ * Test all actions affected with XSS security issue.
+ */
+@Test( groups = { "xss" }, dependsOnMethods = { "testWithCorrectUsernamePassword" }, sequential = true )
+public class XSSSecurityTest
+    extends AbstractArchivaTest
+{
+    public void testDeleteArtifactImmunityToURLCrossSiteScripting()
+    {
+        getSelenium().open( "/archiva/deleteArtifact!doDelete.action?groupId=\"/>1<script>alert('xss')</script>&artifactId=\"/>1<script>alert('xss')</script>&version=\"/>1<script>alert('xss')</script>&repositoryId=\"/>1<script>alert('xss')</script>");
+        assertDeleteArtifactPage();
+        assertTextPresent( "Invalid version." );
+        assertTextPresent( "User is not authorized to delete artifacts in repository '\"/>1<script>alert('xss')</script>'." );
+        assertTextPresent( "Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Repository id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertElementValue("//input[@id='deleteArtifact_groupId']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='deleteArtifact_artifactId']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='deleteArtifact_version']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//select[@id='deleteArtifact_repositoryId']", "internal");
+    }
+
+    public void testDeleteArtifactImmunityToEncodedURLCrossSiteScripting()
+    {
+        getSelenium().open( "/archiva/deleteArtifact!doDelete.action?groupId=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E&artifactId=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E&version=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E&repositoryId=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E");
+        assertDeleteArtifactPage();
+        assertTextPresent( "Invalid version." );
+        assertTextPresent( "User is not authorized to delete artifacts in repository '\"/>1<script>alert('xss')</script>'." );
+        assertTextPresent( "Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Repository id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertElementValue("//input[@id='deleteArtifact_groupId']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='deleteArtifact_artifactId']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='deleteArtifact_version']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//select[@id='deleteArtifact_repositoryId']", "internal");
+    }
+
+    public void testEditAppearanceImmunityToURLCrossSiteScripting()
+    {
+        getSelenium().open( "/archiva/admin/configureAppearance.action?organisationName=<script>alert('xss')</script>&organisationUrl=<script>alert('xss')</script>&organisationLogo=<script>alert('xss')</script>");
+        assertAppearancePage();
+        assertXpathCount("//td[text()=\"<script>alert('xss')</script>\"]", 1);
+        assertXpathCount("//code[text()=\"<script>alert('xss')</script>\"]", 2);
+
+    }
+
+    public void testEditAppearanceImmunityToEncodedURLCrossSiteScripting()
+    {
+        getSelenium().open( "/archiva/admin/configureAppearance.action?organisationName=%3Cscript%3Ealert('xss')%3C%2Fscript%3E&organisationUrl=%3Cscript%3Ealert('xss')%3C%2Fscript%3E&organisationLogo=%3Cscript%3Ealert('xss')%3C%2Fscript%3E");
+        assertAppearancePage();
+        assertXpathCount("//td[text()=\"<script>alert('xss')</script>\"]", 1);
+        assertXpathCount("//code[text()=\"<script>alert('xss')</script>\"]", 2);
+    }
+
+    public void testAddLegacyArtifactImmunityToURLCrossSiteScripting()
+    {
+        getSelenium().open( "/archiva/admin/addLegacyArtifactPath!commit.action?legacyArtifactPath.path=\"/>1<script>alert('xss')</script>&groupId=\"/>1<script>alert('xss')</script>&artifactId=\"/>1<script>alert('xss')</script>&version=\"/>1<script>alert('xss')</script>&classifier=\"/>1<script>alert('xss')</script>&type=\"/>1<script>alert('xss')</script>");
+        assertAddLegacyArtifactPathPage();
+        assertTextPresent( "Legacy path must only contain alphanumeric characters, forward-slashes(/), back-slashes(\\), underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Version must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Classifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Type must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertElementValue("//input[@id='addLegacyArtifactPath_legacyArtifactPath_path']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='addLegacyArtifactPath_artifactId']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='addLegacyArtifactPath_version']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='addLegacyArtifactPath_groupId']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='addLegacyArtifactPath_classifier']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='addLegacyArtifactPath_type']", "\"/>1<script>alert('xss')</script>");
+    }
+
+    public void testAddLegacyArtifactImmunityToEncodedURLCrossSiteScripting()
+    {
+        getSelenium().open( "/archiva/admin/addLegacyArtifactPath!commit.action?legacyArtifactPath.path=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E&groupId=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E&artifactId=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E&version=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E&classifier=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E&type=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E");
+        assertAddLegacyArtifactPathPage();
+        assertTextPresent( "Legacy path must only contain alphanumeric characters, forward-slashes(/), back-slashes(\\), underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Version must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Classifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Type must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertElementValue("//input[@id='addLegacyArtifactPath_legacyArtifactPath_path']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='addLegacyArtifactPath_artifactId']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='addLegacyArtifactPath_version']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='addLegacyArtifactPath_groupId']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='addLegacyArtifactPath_classifier']", "\"/>1<script>alert('xss')</script>");
+        assertElementValue("//input[@id='addLegacyArtifactPath_type']", "\"/>1<script>alert('xss')</script>");
+    }
+
+    public void testDeleteNetworkProxyImmunityToURLCrossSiteScripting()
+    {
+        getSelenium().open( "/archiva/admin/deleteNetworkProxy!confirm.action?proxyid=\"/>1<script>alert('xss')</script>");
+        assertTextPresent( "Security Alert - Invalid Token Found" );
+        assertTextPresent( "Possible CSRF attack detected! Invalid token found in the request." );
+    }
+
+    public void testDeleteNetworkProxyImmunityToEncodedURLCrossSiteScripting()
+    {
+        getSelenium().open( "/archiva/admin/deleteNetworkProxy!confirm.action?proxyid=%22%2F%3E1%3Cscript%3Ealert('xss')%3C%2Fscript%3E");
+        assertTextPresent( "Security Alert - Invalid Token Found" );
+        assertTextPresent( "Possible CSRF attack detected! Invalid token found in the request." );
+    }
+
+    public void testAddManagedRepositoryImmunityToInputFieldCrossSiteScripting()
+    {
+        goToRepositoriesPage();
+        getSelenium().open( "/archiva/admin/addRepository.action" );
+       addManagedRepository( "test\"><script>alert('xss')</script>", "test\"><script>alert('xss')</script>" , "test\"><script>alert('xss')</script>" , "test\"><script>alert('xss')</script>", "Maven 2.x Repository", "", "-1", "101" );
+        // xss inputs are blocked by validation.
+       assertTextPresent( "Identifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+       assertTextPresent( "Directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+       assertTextPresent( "Repository Name must only contain alphanumeric characters, white-spaces(' '), forward-slashes(/), open-parenthesis('('), close-parenthesis(')'), underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Index directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+        assertTextPresent( "Repository Purge By Retention Count needs to be between 1 and 100.");
+        assertTextPresent( "Repository Purge By Days Older Than needs to be larger than 0.");
+       assertTextPresent( "Invalid cron expression." );
+    }
+
+    public void testEditAppearanceImmunityToInputFieldCrossSiteScripting()
+    {
+        goToAppearancePage();
+        clickLinkWithText( "Edit" );
+        addEditAppearance( "test<script>alert('xss')</script>" , "test<script>alert('xss')</script>" , "test<script>alert('xss')</script>" );
+        // xss inputs are blocked by validation.
+        assertTextPresent( "Organisation name must only contain alphanumeric characters, white-spaces(' '), equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+        assertTextPresent( "You must enter a URL" );
+        assertXpathCount("//span[@class='errorMessage' and text()='You must enter a URL']", 2);
+    }
+
+    public void testEditAppearanceImmunityToCrossSiteScriptingRendering()
+    {
+        goToAppearancePage();
+        clickLinkWithText( "Edit" );
+        addEditAppearance( "xss" , "http://\">test<script>alert(\"xss\")</script>" , "http://\">test<script>alert(\"xss\")</script>" );
+        // escaped html/url prevents cross-site scripting exploits
+        assertXpathCount("//td[text()=\"xss\"]", 1);
+        assertXpathCount("//code[text()='http://\">test<script>alert(\"xss\")</script>']", 2);
+    }
+
+    public void testAddLegacyArtifactPathImmunityToInputFieldCrossSiteScripting()
+    {
+        goToLegacySupportPage();
+       clickLinkWithText( "Add" );
+        addLegacyArtifactPath( "test<script>alert('xss')</script>" , "test<script>alert('xss')</script>" , "test<script>alert('xss')</script>" , "test<script>alert('xss')</script>" , "test<script>alert('xss')</script>" , "test<script>alert('xss')</script>");
+       // xss inputs are blocked by validation.
+        assertTextPresent( "Legacy path must only contain alphanumeric characters, forward-slashes(/), back-slashes(\\), underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Version must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Classifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Type must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+    }
+
+    public void testAddNetworkProxyImmunityToInputFieldCrossSiteScripting()
+    {
+        goToNetworkProxiesPage();
+       addNetworkProxy( "test<script>alert('xss')</script>", "test<script>alert('xss')</script>", "test<script>alert('xss')</script>", "test<script>alert('xss')</script>", "test<script>alert('xss')</script>", "");
+       // xss inputs are blocked by validation.
+        assertTextPresent( "Proxy id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
+        assertTextPresent( "Protocol must only contain alphanumeric characters, forward-slashes(/), back-slashes(\\), dots(.), colons(:), and dashes(-)." );
+        assertTextPresent( "Host must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
+        assertTextPresent( "Invalid field value for field \"proxy.port\"." );
+        assertTextPresent( "Username must only contain alphanumeric characters, at's(@), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), and dashes(-)." );
+    }
+}
\ No newline at end of file
index 3a2131dcbadda4d65285d5f2eb2eb1688530ce2d..f6b9fb373f31eacb54aa636b61c01af44df87c8f 100644 (file)
@@ -552,6 +552,104 @@ public abstract class AbstractArchivaTest
        clickButtonWithValue( "Add Repository" );
     }
 
+    // artifact management
+    public void assertDeleteArtifactPage()
+    {
+        assertPage( "Apache Archiva \\ Delete Artifact" );
+        assertTextPresent( "Delete Artifact" );
+        assertTextPresent( "Group Id*:" );
+        assertTextPresent( "Artifact Id*:" );
+        assertTextPresent( "Version*:" );
+        assertTextPresent( "Repository Id:" );
+        assertElementPresent( "groupId" );
+        assertElementPresent( "artifactId" );
+        assertElementPresent( "version" );
+        assertElementPresent( "repositoryId" );
+        assertButtonWithValuePresent( "Submit" );
+    }
+
+    // network proxies
+    public void goToNetworkProxiesPage()
+    {
+        clickLinkWithText( "Network Proxies" );
+        assertNetworkProxiesPage();
+    }
+
+    public void assertNetworkProxiesPage()
+    {
+       assertPage( "Apache Archiva \\ Administration - Network Proxies" );
+        assertTextPresent( "Administration - Network Proxies" );
+        assertTextPresent( "Network Proxies" );
+        assertLinkPresent( "Add Network Proxy" );
+    }
+
+    public void addNetworkProxy( String identifier, String protocol, String hostname, String port, String username, String password )
+    {
+        //goToNetworkProxiesPage();
+        clickLinkWithText( "Add Network Proxy" );
+        assertAddNetworkProxy();
+        setFieldValue( "proxy.id" , identifier );
+        setFieldValue( "proxy.protocol" , protocol );
+        setFieldValue( "proxy.host" , hostname );
+        setFieldValue( "proxy.port" , port );
+        setFieldValue( "proxy.username" , username );
+        setFieldValue( "proxy.password" , password );
+        clickButtonWithValue( "Save Network Proxy" );
+    }
+
+    public void assertAddNetworkProxy()
+    {
+        assertPage( "Apache Archiva \\ Admin: Add Network Proxy" );
+        assertTextPresent( "Admin: Add Network Proxy" );
+        assertTextPresent( "Add network proxy:" );
+        assertTextPresent( "Identifier*:" );
+        assertTextPresent( "Protocol*:" );
+        assertTextPresent( "Hostname*:" );
+        assertTextPresent( "Port*:" );
+        assertTextPresent( "Username:" );
+        assertTextPresent( "Password:" );
+        assertButtonWithValuePresent( "Save Network Proxy" );
+    }
+
+    // Legacy Support
+    public void goToLegacySupportPage()
+    {
+        getSelenium().open( "/archiva/admin/legacyArtifactPath.action" );
+        assertLegacySupportPage();
+    }
+
+    public void assertLegacySupportPage()
+    {
+       assertPage( "Apache Archiva \\ Administration - Legacy Support" );
+       assertTextPresent( "Administration - Legacy Artifact Path Resolution" );
+       assertTextPresent( "Path Mappings" );
+       assertLinkPresent( "Add" );
+    }
+
+    public void addLegacyArtifactPath( String path, String groupId, String artifactId, String version, String classifier, String type)
+    {
+        assertAddLegacyArtifactPathPage();
+        setFieldValue( "legacyArtifactPath.path" , path );
+        setFieldValue( "groupId" , groupId );
+        setFieldValue( "artifactId" , artifactId );
+        setFieldValue( "version" , version );
+        setFieldValue( "classifier" , classifier );
+        setFieldValue( "type" , type );
+        clickButtonWithValue( "Add Legacy Artifact Path" );
+    }
+
+    public void assertAddLegacyArtifactPathPage()
+    {
+        assertPage( "Apache Archiva \\ Admin: Add Legacy Artifact Path" );
+        assertTextPresent( "Admin: Add Legacy Artifact Path" );
+        assertTextPresent( "Enter the legacy path to map to a particular artifact reference, then adjust the fields as necessary." );
+        String element = "addLegacyArtifactPath_legacyArtifactPath_path,addLegacyArtifactPath_groupId,addLegacyArtifactPath_artifactId,addLegacyArtifactPath_version,addLegacyArtifactPath_classifier,addLegacyArtifactPath_type";
+        String[] arrayElement = element.split( "," );
+        for ( String arrayelement : arrayElement )
+                assertElementPresent( arrayelement );
+        assertButtonWithValuePresent( "Add Legacy Artifact Path" );
+    }
+
     protected void logout()
     {
         clickLinkWithText("Logout");
index 433c040149fa2cd78b2ec0d9bde71e446d514e79..0847a6cc96689b00c1dbb44b19d8b831352b14e9 100644 (file)
@@ -55,58 +55,4 @@ public abstract class AbstractArtifactManagementTest
                selectValue( "repositoryId" ,  repositoryId );
                clickButtonWithValue( "Submit" ) ;
        }
-       
-       public void assertDeleteArtifactPage()
-       {
-               assertPage( "Apache Archiva \\ Delete Artifact" );
-               assertTextPresent( "Delete Artifact" );
-               assertTextPresent( "Group Id*:" );
-               assertTextPresent( "Artifact Id*:" );
-               assertTextPresent( "Version*:" );
-               assertTextPresent( "Repository Id:" );
-               assertElementPresent( "groupId" );
-               assertElementPresent( "artifactId" );
-               assertElementPresent( "version" );
-               assertElementPresent( "repositoryId" );
-               assertButtonWithValuePresent( "Submit" );
-       }
-       
-       // Legacy Support
-       public void goToLegacySupportPage()
-       {
-               getSelenium().open( "/archiva/admin/legacyArtifactPath.action" );
-               assertLegacySupportPage();
-       }
-       
-       public void assertLegacySupportPage()
-       {
-               assertPage( "Apache Archiva \\ Administration - Legacy Support" );
-               assertTextPresent( "Administration - Legacy Artifact Path Resolution" );
-               assertTextPresent( "Path Mappings" );
-               assertLinkPresent( "Add" );
-       }
-       
-       public void addLegacyArtifactPath( String path, String groupId, String artifactId, String version, String classifier, String type)
-       {
-               assertAddLegacyArtifactPathPage();
-               setFieldValue( "legacyArtifactPath.path" , path );
-               setFieldValue( "groupId" , groupId );
-               setFieldValue( "artifactId" , artifactId );
-               setFieldValue( "version" , version );
-               setFieldValue( "classifier" , classifier );
-               setFieldValue( "type" , type );
-               clickButtonWithValue( "Add Legacy Artifact Path" );
-       }
-       
-       public void assertAddLegacyArtifactPathPage()
-       {
-               assertPage( "Apache Archiva \\ Admin: Add Legacy Artifact Path" );
-               assertTextPresent( "Admin: Add Legacy Artifact Path" );
-               assertTextPresent( "Enter the legacy path to map to a particular artifact reference, then adjust the fields as necessary." );
-               String element = "addLegacyArtifactPath_legacyArtifactPath_path,addLegacyArtifactPath_groupId,addLegacyArtifactPath_artifactId,addLegacyArtifactPath_version,addLegacyArtifactPath_classifier,addLegacyArtifactPath_type";
-               String[] arrayElement = element.split( "," );
-               for ( String arrayelement : arrayElement )
-                       assertElementPresent( arrayelement );
-               assertButtonWithValuePresent( "Add Legacy Artifact Path" );
-       }
 }
index 7595a335fffc1c4e1293a48716346cbc4597c7ae..77dad4db37a49f5916f8123e081b33f295cdd4bc 100644 (file)
@@ -177,47 +177,6 @@ public abstract class AbstractRepositoryTest
        ///////////////////////////////
        // network proxies
        ///////////////////////////////
-       public void goToNetworkProxiesPage()
-       {
-               clickLinkWithText( "Network Proxies" );
-               assertNetworkProxiesPage();
-       }
-       
-       public void assertNetworkProxiesPage()
-       {
-               assertPage( "Apache Archiva \\ Administration - Network Proxies" );
-               assertTextPresent( "Administration - Network Proxies" );
-               assertTextPresent( "Network Proxies" );
-               assertLinkPresent( "Add Network Proxy" );
-       }
-       
-       public void assertAddNetworkProxy()
-       {
-               assertPage( "Apache Archiva \\ Admin: Add Network Proxy" );
-               assertTextPresent( "Admin: Add Network Proxy" );
-               assertTextPresent( "Add network proxy:" );
-               assertTextPresent( "Identifier*:" );
-               assertTextPresent( "Protocol*:" );
-               assertTextPresent( "Hostname*:" );
-               assertTextPresent( "Port*:" );
-               assertTextPresent( "Username:" );
-               assertTextPresent( "Password:" );
-               assertButtonWithValuePresent( "Save Network Proxy" );
-       }
-       
-       public void addNetworkProxy( String identifier, String protocol, String hostname, String port, String username, String password )
-       {
-               //goToNetworkProxiesPage();
-               clickLinkWithText( "Add Network Proxy" );
-               assertAddNetworkProxy();
-               setFieldValue( "proxy.id" , identifier );
-               setFieldValue( "proxy.protocol" , protocol );
-               setFieldValue( "proxy.host" , hostname );
-               setFieldValue( "proxy.port" , port );
-               setFieldValue( "proxy.username" , username );
-               setFieldValue( "proxy.password" , password );
-               clickButtonWithValue( "Save Network Proxy" );
-       }
        
        public void editNetworkProxies( String fieldName, String value)
        {
@@ -299,6 +258,21 @@ public abstract class AbstractRepositoryTest
                //TODO
                clickButtonWithValue( "Update Repository" );
        }
+
+        public void editManagedRepository(String name, String directory, String indexDirectory, String type, String cron, String daysOlder, String retentionCount)
+        {
+                goToRepositoriesPage();
+               clickLinkWithXPath( "//div[@id='contentArea']/div/div[5]/div[1]/a[1]/img" );
+               assertPage( "Apache Archiva \\ Admin: Edit Managed Repository" );
+                setFieldValue( "repository.name" , name );
+                setFieldValue( "repository.location" , directory );
+                setFieldValue( "repository.indexDir" , indexDirectory );
+                selectValue( "repository.layout", type );
+                setFieldValue( "repository.refreshCronExpression" , cron );
+                setFieldValue( "repository.daysOlder" , daysOlder );
+                setFieldValue( "repository.retentionCount" , retentionCount );
+                clickButtonWithValue( "Update Repository" );
+        }
        
        public void deleteManagedRepository()
        {
index 888e89c4141572ef086d4234b3750c167d21c8b0..98d4b6f8d48d15b4962592b7e8ea862c0feeb16d 100644 (file)
@@ -399,5 +399,14 @@ public abstract class AbstractSeleniumTest {
        {
           Assert.assertFalse( getSelenium().isChecked( locator ) );
        }
-           
+
+        public void assertXpathCount(String locator, int expectedCount)
+        {
+            Assert.assertEquals( getSelenium().getXpathCount(locator).intValue(), expectedCount );
+        }
+
+        public void assertElementValue(String locator, String expectedValue)
+        {
+            Assert.assertEquals(getSelenium().getValue(locator), expectedValue);
+        }
 }
index 7d2d62b2569e794a5fb84d10d1d8ac7e02e31220..ecb14aeb96b948beee2b9fe453f19588d0018208 100644 (file)
@@ -60,6 +60,7 @@ import org.apache.maven.archiva.security.UserRepositories;
 
 import com.opensymphony.xwork2.Preparable;
 import com.opensymphony.xwork2.Validateable;
+import org.apache.commons.lang.StringUtils;
 
 /**
  * Delete an artifact. Metadata will be updated if one exists, otherwise it would be created.
@@ -381,6 +382,9 @@ public class DeleteArtifactAction
         {
             addActionError( e.getMessage() );
         }
+
+        // trims all request parameter values, since the trailing/leading white-spaces are ignored during validation.
+        trimAllRequestParameterValues();
     }
 
     private List<String> getManagableRepos()
@@ -404,4 +408,27 @@ public class DeleteArtifactAction
         }
         return Collections.emptyList();
     }
+
+    private void trimAllRequestParameterValues()
+    {
+        if(StringUtils.isNotEmpty(groupId))
+        {
+            groupId = groupId.trim();
+        }
+
+        if(StringUtils.isNotEmpty(artifactId))
+        {
+            artifactId = artifactId.trim();
+        }
+
+        if(StringUtils.isNotEmpty(version))
+        {
+            version = version.trim();
+        }
+
+        if(StringUtils.isNotEmpty(repositoryId))
+        {
+            repositoryId = repositoryId.trim();
+        }
+    }
 }
index a6b65f8d347b6dd74c09bc09b0c924a830200be8..c32b8233a38eed35bbb5ceb32dc7f8d124dd6423 100644 (file)
@@ -19,6 +19,8 @@ package org.apache.maven.archiva.web.action.admin.appearance;
  * under the License.
  */
 
+import com.opensymphony.xwork2.Validateable;
+import org.apache.commons.lang.StringUtils;
 import org.apache.maven.archiva.configuration.Configuration;
 import org.apache.maven.archiva.configuration.IndeterminateConfigurationException;
 import org.apache.maven.archiva.configuration.OrganisationInformation;
@@ -38,7 +40,7 @@ import org.codehaus.redback.integration.interceptor.SecureActionException;
  */
 public class EditOrganisationInfoAction
     extends AbstractAppearanceAction
-    implements SecureAction
+    implements SecureAction, Validateable
 {
     @Override
     public String execute()
@@ -70,4 +72,28 @@ public class EditOrganisationInfoAction
         bundle.addRequiredAuthorization( ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION, Resource.GLOBAL );
         return bundle;
     }
+    
+    public void validate()
+    {
+        // trim all unecessary trailing/leading white-spaces; always put this statement before the closing braces(after all validation).
+        trimAllRequestParameterValues();
+    }
+    
+    private void trimAllRequestParameterValues()
+    {
+        if(StringUtils.isNotEmpty(super.getOrganisationName()))
+        {
+            super.setOrganisationName(super.getOrganisationName().trim());
+        }
+
+        if(StringUtils.isNotEmpty(super.getOrganisationUrl()))
+        {
+            super.setOrganisationUrl(super.getOrganisationUrl().trim());
+        }
+
+        if(StringUtils.isNotEmpty(super.getOrganisationLogo()))
+        {
+            super.setOrganisationLogo(super.getOrganisationLogo().trim());
+        }
+    }
 }
index f3d4a36a263ed0868d0c4970fcf9f5a4878484dc..18a266ccdedecaa52f5d21d97a3b4f5df24909e5 100644 (file)
@@ -28,6 +28,8 @@ import org.apache.maven.archiva.repository.ManagedRepositoryContent;
 import org.codehaus.plexus.registry.RegistryException;
 
 import com.opensymphony.xwork2.Preparable;
+import com.opensymphony.xwork2.Validateable;
+import org.apache.commons.lang.StringUtils;
 import org.apache.maven.archiva.web.action.PlexusActionSupport;
 
 /**
@@ -38,7 +40,7 @@ import org.apache.maven.archiva.web.action.PlexusActionSupport;
  */
 public class AddLegacyArtifactPathAction
     extends PlexusActionSupport
-    implements Preparable
+    implements Preparable, Validateable
 {
     /**
      * @plexus.requirement
@@ -110,6 +112,12 @@ public class AddLegacyArtifactPathAction
         this.legacyArtifactPath = legacyArtifactPath;
     }
 
+    public void validate()
+    {
+        // trim all unecessary trailing/leading white-spaces; always put this statement before the closing braces(after all validation).
+        trimAllRequestParameterValues();
+    }
+
     protected String saveConfiguration( Configuration configuration )
     {
         try
@@ -131,6 +139,39 @@ public class AddLegacyArtifactPathAction
         return SUCCESS;
     }
 
+    private void trimAllRequestParameterValues()
+    {
+        if(StringUtils.isNotEmpty(legacyArtifactPath.getPath()))
+        {
+            legacyArtifactPath.setPath(legacyArtifactPath.getPath().trim());
+        }
+
+        if(StringUtils.isNotEmpty(groupId))
+        {
+            groupId = groupId.trim();
+        }
+
+        if(StringUtils.isNotEmpty(artifactId))
+        {
+            artifactId = artifactId.trim();
+        }
+
+        if(StringUtils.isNotEmpty(version))
+        {
+            version = version.trim();
+        }
+
+        if(StringUtils.isNotEmpty(classifier))
+        {
+            classifier = classifier.trim();
+        }
+
+        if(StringUtils.isNotEmpty(type))
+        {
+            type = type.trim();
+        }
+    }
+
     public String getGroupId()
     {
         return groupId;
index ec408deab4e7e3739a6e23df9559074906dfe18d..3299bc3b78775ba0ed7eacf4e1925a50163e54ef 100644 (file)
@@ -20,6 +20,7 @@ package org.apache.maven.archiva.web.action.admin.networkproxies;
  */
 
 import com.opensymphony.xwork2.Preparable;
+import com.opensymphony.xwork2.Validateable;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.functors.NotPredicate;
 import org.apache.commons.lang.StringUtils;
@@ -44,7 +45,7 @@ import org.codehaus.redback.integration.interceptor.SecureActionException;
  */
 public class ConfigureNetworkProxyAction
     extends PlexusActionSupport
-    implements SecureAction, Preparable
+    implements SecureAction, Preparable, Validateable
 {
     /**
      * @plexus.requirement
@@ -169,6 +170,12 @@ public class ConfigureNetworkProxyAction
         return saveConfiguration();
     }
 
+    public void validate()
+    {
+        // trim all unecessary trailing/leading white-spaces; always put this statement before the closing braces(after all validation).
+        trimAllRequestParameterValues();
+    }
+
     public void setMode( String mode )
     {
         this.mode = mode;
@@ -225,4 +232,32 @@ public class ConfigureNetworkProxyAction
 
         return SUCCESS;
     }
+
+    private void trimAllRequestParameterValues()
+    {
+        if(StringUtils.isNotEmpty(proxy.getId()))
+        {
+            proxy.setId(proxy.getId().trim());
+        }
+        
+        if(StringUtils.isNotEmpty(proxy.getHost()))
+        {
+            proxy.setHost(proxy.getHost().trim());
+        }
+
+        if(StringUtils.isNotEmpty(proxy.getPassword()))
+        {
+            proxy.setPassword(proxy.getPassword().trim());
+        }
+
+        if(StringUtils.isNotEmpty(proxy.getProtocol()))
+        {
+            proxy.setProtocol(proxy.getProtocol().trim());
+        }
+
+        if(StringUtils.isNotEmpty(proxy.getUsername()))
+        {
+            proxy.setUsername(proxy.getUsername().trim());
+        }
+    }
 }
index 97151c8163fbbb7f33bd7d9804933930bf482258..e7f211ae1940df38f06e9176075205461352a1c5 100644 (file)
@@ -29,6 +29,7 @@ import org.codehaus.plexus.redback.role.RoleManagerException;
 import org.codehaus.plexus.scheduler.CronExpressionValidator;
 import java.io.File;
 import java.io.IOException;
+import org.apache.commons.lang.StringUtils;
 
 /**
  * AddManagedRepositoryAction 
@@ -135,6 +136,32 @@ public class AddManagedRepositoryAction
         {
             addFieldError( "repository.refreshCronExpression", "Invalid cron expression." );
         }
+
+        // trim all unecessary trailing/leading white-spaces; always put this statement before the closing braces(after all validation).
+        trimAllRequestParameterValues();
+    }
+
+    private void trimAllRequestParameterValues()
+    {
+        if(StringUtils.isNotEmpty(repository.getId()))
+        {
+            repository.setId(repository.getId().trim());
+        }
+
+        if(StringUtils.isNotEmpty(repository.getName()))
+        {
+            repository.setName(repository.getName().trim());
+        }
+
+        if(StringUtils.isNotEmpty(repository.getLocation()))
+        {
+            repository.setLocation(repository.getLocation().trim());
+        }
+        
+        if(StringUtils.isNotEmpty(repository.getIndexDir()))
+        {
+            repository.setIndexDir(repository.getIndexDir().trim());
+        }
     }
 
     public ManagedRepositoryConfiguration getRepository()
index f128ba152d20cc4eedfb26822ea5ca14bb2018e5..9e78dbbeac29323c8fcb8641a9dec02eebe7b965 100644 (file)
@@ -167,6 +167,8 @@ public class EditManagedRepositoryAction
         {
             addFieldError( "repository.refreshCronExpression", "Invalid cron expression." );
         }
+
+        trimAllRequestParameterValues();
     }
 
     private void resetStatistics( boolean reset )
@@ -189,7 +191,30 @@ public class EditManagedRepositoryAction
                 repoContentStatsDao.deleteRepositoryContentStatistics( stats );
             }
         }
-       } 
+    }
+
+    private void trimAllRequestParameterValues()
+    {
+        if(StringUtils.isNotEmpty(repository.getId()))
+        {
+            repository.setId(repository.getId().trim());
+        }
+
+        if(StringUtils.isNotEmpty(repository.getName()))
+        {
+            repository.setName(repository.getName().trim());
+        }
+
+        if(StringUtils.isNotEmpty(repository.getLocation()))
+        {
+            repository.setLocation(repository.getLocation().trim());
+        }
+
+        if(StringUtils.isNotEmpty(repository.getIndexDir()))
+        {
+            repository.setIndexDir(repository.getIndexDir().trim());
+        }
+    }
 
     public String getRepoid()
     {
index dcef342d032b89f95720d6a05586f766e9a79946..bfe08fa1fe5aa3d3150fa7a2ac79b50e85acc193 100644 (file)
 <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
     "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
 
+<!-- validate temporarily-trimmed inputs, actual values are then carried over to the action class to be trimmed once more. -->
 <validators>
   <field name="groupId">
     <field-validator type="requiredstring">
       <message>You must enter a groupId.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]+$</param>
+        <message>Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="artifactId">
     <field-validator type="requiredstring">
       <message>You must enter an artifactId.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]+$</param>
+        <message>Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
+  <!-- version's validation is inside the validate() method of the action class -->
   <field name="version">
     <field-validator type="requiredstring">
       <message>You must enter a version.</message>
     </field-validator>
-  </field>   
+  </field>
+  <field name="repositoryId">
+    <!-- no requiredstring validation, because there was none before(being consistent). -->
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]*$</param>
+        <message>Repository id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
+  </field>
 </validators>
\ No newline at end of file
index 38b3bcfa89782cda72590db20b1ab264c3a7a899..df93a3bbcd787d14419c7b4982caf3f822b7f2b6 100644 (file)
         <field-validator type="requiredstring">
             <message>You must enter a name</message>
         </field-validator>
+        <field-validator type="regex">
+            <param name="trim">true</param>
+            <param name="expression">^([-a-zA-Z0-9._/~:?!&amp;=\\]|\s)+$</param>
+            <message>Organisation name must only contain alphanumeric characters, white-spaces(' '), equals(=), question-marks(?), exclamation-points(!), ampersands(&amp;), forward-slashes(/), back-slashes(\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).</message>
+        </field-validator>
     </field>
     <field name="organisationUrl">
         <field-validator type="url">
index 1725a33ec88055135b3a18943bc22ff362066cfd..bbf09dd9de24c6fe6daf7420c8cdc1f642fff4a3 100644 (file)
 <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
     "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
 
+<!-- validate temporarily-trimmed inputs, actual values are then carried over to the action class to be trimmed once more. -->
 <validators>
   <field name="legacyArtifactPath.path">
     <field-validator type="requiredstring">
       <message>You must enter a legacy path.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[-a-zA-Z0-9._/\\]+$</param>
+        <message>Legacy path must only contain alphanumeric characters, forward-slashes(/), back-slashes(\), underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="groupId">
     <field-validator type="requiredstring">
       <message>You must enter a groupId.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]+$</param>
+        <message>Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="artifactId">
     <field-validator type="requiredstring">
       <message>You must enter an artifactId.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]+$</param>
+        <message>Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="version">
     <field-validator type="requiredstring">
       <message>You must enter a version.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]+$</param>
+        <message>Version must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
+  </field>
+  <field name="classifier">
+    <!-- no requiredstring validation, because there was none before(being consistent). -->
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]*$</param>
+        <message>Classifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="type">
     <field-validator type="requiredstring">
       <message>You must enter a type.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]+$</param>
+        <message>Type must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
 </validators>
\ No newline at end of file
index 5e39f8d7e5178281eb38185e74f25b14a0b5874b..669b3b102f8f561f03c8430b408027373d063356 100644 (file)
       <param name="trim">true</param>
       <message>You must enter an identifier of 4 or more than 4 characters.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]+$</param>
+        <message>Proxy id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="proxy.protocol">
     <field-validator type="requiredstring">
       <param name="trim">true</param>
       <message>You must enter a protocol.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[-a-zA-Z0-9./:\\]+$</param>
+        <message>Protocol must only contain alphanumeric characters, forward-slashes(/), back-slashes(\), dots(.), colons(:), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="proxy.host">
     <field-validator type="requiredstring">
       <param name="trim">true</param>
       <message>You must enter a host.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[-a-zA-Z0-9._/~:?!&amp;=\\]+$</param>
+        <message>Host must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&amp;), forward-slashes(/), back-slashes(\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="proxy.port">
     <field-validator type="required">
 -->
       <message>Port needs to be larger than ${min}</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[0-9]+$</param>
+        <message>Port must only contain numeric characters.</message>
+    </field-validator>
+  </field>
+  <field name="proxy.username">
+    <!-- no requiredstring validation, because there was none before(being consistent). -->
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[-a-zA-Z0-9.@/_\\]*$</param>
+        <message>Username must only contain alphanumeric characters, at's(@), forward-slashes(/), back-slashes(\), underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
 </validators>
index 23f4cb49582821081e8879a85a0830689e8f0e90..8e779075930aad0ab83a397c1bdb9270c4f4647a 100644 (file)
     <field-validator type="requiredstring">
       <message>You must enter a repository identifier.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]+$</param>
+        <message>Identifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="repository.location">
     <field-validator type="requiredstring">
       <message>You must enter a directory.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[-a-zA-Z0-9._/~:?!&amp;=\\]+$</param>
+        <message>Directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&amp;), forward-slashes(/), back-slashes(\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).</message>
+    </field-validator>
+  </field>
+  <field name="repository.indexDir">
+    <!-- no requiredstring validation, because there was none before(being consistent). -->
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[-a-zA-Z0-9._/~:?!&amp;=\\]*$</param>
+        <message>Index directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&amp;), forward-slashes(/), back-slashes(\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="repository.name">
     <field-validator type="requiredstring">
       <message>You must enter a repository name.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^([a-zA-Z0-9.)/_(-]|\s)+$</param>
+        <message>Repository Name must only contain alphanumeric characters, white-spaces(' '), forward-slashes(/), open-parenthesis('('), close-parenthesis(')'),  underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>   
   <field name="repository.retentionCount">
     <field-validator type="int">
index 4ce434a43ed03bc96122f9332340d56867b4af77..b00981f06d752597896e6240fde8a44d988d30c8 100644 (file)
     <field-validator type="requiredstring">
       <message>You must enter a repository identifier.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[a-zA-Z0-9._-]+$</param>
+        <message>Identifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="repository.location">
     <field-validator type="requiredstring">
       <message>You must enter a directory.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[-a-zA-Z0-9._/~:?!&amp;=\\]+$</param>
+        <message>Directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&amp;), forward-slashes(/), back-slashes(\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).</message>
+    </field-validator>
+  </field>
+  <field name="repository.indexDir">
+    <!-- no requiredstring validation, because there was none before(being consistent). -->
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^[-a-zA-Z0-9._/~:?!&amp;=\\]*$</param>
+        <message>Index directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&amp;), forward-slashes(/), back-slashes(\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="repository.name">
     <field-validator type="requiredstring">
       <message>You must enter a repository name.</message>
     </field-validator>
+    <field-validator type="regex">
+        <param name="trim">true</param>
+        <param name="expression">^([a-zA-Z0-9.)/_(-]|\s)+$</param>
+        <message>Repository Name must only contain alphanumeric characters, white-spaces(' '), forward-slashes(/), open-parenthesis('('), close-parenthesis(')'),  underscores(_), dots(.), and dashes(-).</message>
+    </field-validator>
   </field>
   <field name="repository.retentionCount">
     <field-validator type="int">
       <param name="min">1</param>
       <param name="max">100</param>
       <message>Repository Purge By Retention Count needs to be between ${min} and ${max}.</message>
-    </field-validator>    
+    </field-validator>
   </field>
   <field name="repository.daysOlder">
     <field-validator type="int">
       <param name="min">0</param>
       <message>Repository Purge By Days Older Than needs to be larger than ${min}.</message>
-    </field-validator>    
+    </field-validator>
   </field>
 </validators>
index f10a3acfd2ced0c4ac9c3a6d6e6646139dbcac93..1e2f4e2134a73f7fb634920c62521dd8fea00e2d 100644 (file)
   }\r
   </script>\r
 \r
-  <s:actionmessage/>\r
-  <s:actionerror/>\r
+  <%-- changed the structure of displaying errorMessages & actionMessages in order for them to be escaped. --%>\r
+  <s:if test="hasActionErrors()">\r
+      <ul>\r
+      <s:iterator value="actionErrors">\r
+          <li><span class="errorMessage"><s:property escape="true" /></span></li>\r
+      </s:iterator>\r
+      </ul>\r
+  </s:if>\r
+  <s:if test="hasActionMessages()">\r
+      <ul>\r
+      <s:iterator value="actionMessages">\r
+          <li><span class="actionMessage"><s:property escape="true" /></span></li>\r
+      </s:iterator>\r
+      </ul>\r
+  </s:if>\r
+\r
   <s:form method="post" action="addLegacyArtifactPath!commit" namespace="/admin" validate="true">\r
     <s:textfield name="legacyArtifactPath.path" label="Path" size="50" required="true" onchange="parse( this.value )"/>\r
     <s:textfield name="groupId" label="GroupId" size="20" required="true"/>\r
index 1581594901c372fb54c25486ecb8227e4990b9f3..d084f4dd2ab3183a42a26c734ab624fb72bda14e 100644 (file)
 <h1>Admin: Add Managed Repository</h1>
 
 <div id="contentArea">
-  <s:actionerror/>
-  <s:actionmessage/>
+  <%-- changed the structure of displaying errorMessages & actionMessages in order for them to be escaped. --%>
+  <s:if test="hasActionErrors()">
+      <ul>
+      <s:iterator value="actionErrors">
+          <li><span class="errorMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
+  <s:if test="hasActionMessages()">
+      <ul>
+      <s:iterator value="actionMessages">
+          <li><span class="actionMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
   <s:form method="post" action="addRepository!commit" namespace="/admin" validate="true">
     <s:textfield name="repository.id" label="Identifier" size="10" required="true"/>
     <%@ include file="/WEB-INF/jsp/admin/include/repositoryForm.jspf" %>
index 55d360d882a9183af2492de0743d4bf0ef1753e8..cd5438c10d11a7648a0e92de7767a30f0c5549d7 100644 (file)
   <a href="<s:url action='editAppearance' />">Change your appearance</a>
 </p>
 
+<%-- used c:out in displaying EL's so that they are escaped --%>
 <h3>Organization Information</h3>
 <table>
   <tr>
     <th>Name</th>
-    <td>${organisationName}</td>
+    <td><c:out value="${organisationName}" /></td>
   </tr>
   <tr>
     <th>URL</th>
-    <td><a href="${organisationUrl}">
-      <code>${organisationUrl}</code>
+    <td><a href='<c:out value="${organisationUrl}" />'>
+      <code><c:out value="${organisationUrl}" /></code>
     </a></td>
   </tr>
   <tr>
     <th>Logo URL</th>
     <td>
-      <code>${organisationLogo}</code>
+      <code><c:out value="${organisationLogo}" /></code>
     </td>
   </tr>
   <c:if test="${!empty (organisationLogo)}">
     <tr>
       <th>&nbsp;</th>
-      <td><img src="${organisationLogo}"
-        title="${organisationName}" border="0" alt="" /></td>
+      <td><img src='<c:out value="${organisationLogo}" />'
+               title='<c:out value="${organisationName}" />' border="0" alt="" /></td>
     </tr>
   </c:if>
 </table>
index e30b19f81945dba3b72bd0f366a5395d1c509ab8..09ca17e0a5773ae8a8bd4ccda858db87eff2dfa9 100644 (file)
     the following managed repository?
   </p>
 
+  <%-- used c:out in displaying EL's so that they are escaped --%>
   <div class="infobox">
     <table class="infotable">
       <tr>
         <td>ID:</td>
-        <td><code>${repository.id}</code></td>
+        <td><code><c:out value="${repository.id}" /></code></td>
       </tr>
       <tr>
         <td>Name:</td>
-        <td>${repository.name}</td>
+        <td><c:out value="${repository.name}" /></td>
       </tr>
       <tr>
         <td>Directory:</td>
-        <td>${repository.location}</td>
+        <td><c:out value="${repository.location}" /></td>
       </tr>
       <tr>
         <td>Index Directory:</td>
-        <td>${repository.indexDir}</td>
+        <td><c:out value="${repository.indexDir}" /></td>
       </tr>
       <tr>
         <td>Type:</td>
       </tr>
       <tr>
         <td>Cron:</td>
-        <td>${repository.refreshCronExpression}</td>
+        <td><c:out value="${repository.refreshCronExpression}" /></td>
       </tr>
       <tr>
         <td>Repository Purge By Days Older Than:</td>
-        <td>${repository.daysOlder}</td>
+        <td><c:out value="${repository.daysOlder}" /></td>
       </tr>
       <tr>
         <td>Repository Purge By Retention Count:</td>
-        <td>${repository.retentionCount}</td>
+        <td><c:out value="${repository.retentionCount}" /></td>
       </tr>
       <tr>
         <td>Releases Included:</td>
index 19156a36e96d939c7aa2f1b62f5df2658d098f5a..49f1d8458ed36612f8978bd85a29e42783c1cece 100644 (file)
@@ -19,6 +19,7 @@
 
 <%@ page contentType="text/html; charset=UTF-8" %>
 <%@ taglib prefix="s" uri="/struts-tags" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 
 <html>
 <head>
 
 <h1>Admin: Delete Network Proxy</h1>
 
-<s:actionerror/>
+  <%-- changed the structure of displaying errorMessages in order for them to be escaped. --%>
+  <s:if test="hasActionErrors()">
+      <ul>
+      <s:iterator value="actionErrors">
+          <li><span class="errorMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
 
 <div id="contentArea">
 
@@ -39,9 +47,9 @@
   <blockquote>
     <strong><span class="statusFailed">WARNING:</span> This operation can not be undone.</strong>
   </blockquote>
-
+  <%-- used c:out in displaying EL's for them to be escaped.  --%>
   <p>
-    Are you sure you want to delete network proxy <code>${proxyid}</code> ?
+      Are you sure you want to delete network proxy <code><c:out value="${proxyid}" /></code> ?
   </p>
 
   <s:form method="post" action="deleteNetworkProxy!delete" namespace="/admin" validate="true">
index 5f925e579e1a6ab3c9388f7a7836e64f5904d501..def8b68f69eb9a531f2f5a79fd5d8526afd0c214 100644 (file)
@@ -19,6 +19,7 @@
 
 <%@ page contentType="text/html; charset=UTF-8" %>
 <%@ taglib prefix="s" uri="/struts-tags" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
 
 <html>
 <head>
 
 <h1>Admin: Delete Managed Repository</h1>
 
-<s:actionerror/>
+<%-- changed the structure of displaying errorMessages in order for them to be escaped. --%>
+<s:if test="hasActionErrors()">
+      <ul>
+      <s:iterator value="actionErrors">
+          <li><span class="errorMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+</s:if>
 
 <div id="contentArea">
 
     Are you sure you want to delete the following managed repository?
   </p>
 
+  <%-- used c:out in displaying EL's so that they are escaped --%>
   <div class="infobox">
     <table class="infotable">
       <tr>
         <td>ID:</td>
-        <td><code>${repository.id}</code></td>
+        <td><code><c:out value="${repository.id}" /></code></td>
       </tr>
       <tr>
         <td>Name:</td>
-        <td>${repository.name}</td>
+        <td><c:out value="${repository.name}" /></td>
       </tr>
       <tr>
         <td>Directory:</td>
-        <td>${repository.location}</td>
+        <td><c:out value="${repository.location}" /></td>
       </tr>
     </table>
   </div>
index 9ec3859fcbd58015403bf09d0e76313e3070ba64..8df7a210da5931e6d4e8e4d49cfc0422a88051d8 100644 (file)
 </p>
 
 <s:set name="editOrganisationInfo" value="editOrganisationInfo"/>
-<s:actionmessage/>
+<%-- changed the structure of displaying actionMessages in order for them to be escaped. --%>
+<s:if test="hasActionMessages()">
+      <ul>
+      <s:iterator value="actionMessages">
+          <li><span class="actionMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+</s:if>
 <s:form method="post" action="saveAppearance" namespace="/admin" validate="true" theme="xhtml">
     <s:textfield name="organisationName" value="%{#attr.organisationName}" label="Name" size="50"  />
     <s:textfield name="organisationUrl" value="%{#attr.organisationUrl}" label="URL" size="50"/>
index f7dd33ec07fd47e2cdc2c4a3002d28db777e7d2f..56af90dad16591874c22325320da69fc8d07337e 100644 (file)
 
 <div id="contentArea">
 
-  <h2>${addedit} network proxy: ${networkProxyName}</h2>
+  <h2>${addedit} network proxy: <c:out value="${networkProxyName}" /></h2>
 
-  <s:actionerror/> 
-  <s:actionmessage/>
+  <%-- changed the structure of displaying errorMessages & actionMessages in order for them to be escaped. --%>
+  <s:if test="hasActionErrors()">
+      <ul>
+      <s:iterator value="actionErrors">
+          <li><span class="errorMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
+  <s:if test="hasActionMessages()">
+      <ul>
+      <s:iterator value="actionMessages">
+          <li><span class="actionMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
   
   <s:form method="post" action="saveNetworkProxy" namespace="/admin">
     <s:hidden name="mode"/>
@@ -66,7 +79,7 @@
   </s:form>
 
   <script type="text/javascript">
-    document.getElementById("saveNetworkProxy_host").focus();
+        document.getElementById("saveNetworkProxy_host").focus();
   </script>
 
 </div>
index 5a0b482a040047b7968945218f946af3dfb14338..2d3e956460389a4db385e2b5139b21340c33da01 100644 (file)
 
 <h1>Admin: Edit Managed Repository</h1>
 
-<s:actionerror/>
+<%-- changed the structure of displaying errorMessages & actionMessages in order for them to be escaped. --%>
+<s:if test="hasActionErrors()">
+      <ul>
+      <s:iterator value="actionErrors">
+          <li><span class="errorMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+</s:if>
 
 <div id="contentArea">
 
-  <s:actionmessage/>
+  <s:if test="hasActionMessages()">
+      <ul>
+      <s:iterator value="actionMessages">
+          <li><span class="actionMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
   <s:form method="post" action="editRepository!commit" namespace="/admin" validate="false">
     <s:hidden name="repository.id"/>
     <s:label label="ID" name="repository.id" />
index 2cb6bdcae79f99604dfa44aba691b293459bb198..8ad83c25971c2a43428d1915e15ea2aee4e63c5b 100644 (file)
 \r
 <div id="contentArea">\r
 \r
-<s:actionerror/>\r
-<s:actionmessage/>\r
+<%-- changed the structure of displaying errorMessages & actionMessages in order for them to be escaped. --%>\r
+<s:if test="hasActionErrors()">\r
+      <ul>\r
+      <s:iterator value="actionErrors">\r
+          <li><span class="errorMessage"><s:property escape="true" /></span></li>\r
+      </s:iterator>\r
+      </ul>\r
+  </s:if>\r
+  <s:if test="hasActionMessages()">\r
+      <ul>\r
+      <s:iterator value="actionMessages">\r
+          <li><span class="actionMessage"><s:property escape="true" /></span></li>\r
+      </s:iterator>\r
+      </ul>\r
+  </s:if>\r
 \r
 <div class="admin">\r
 <div class="controls">\r
 </c:choose>\r
 \r
 <div class="legacyArtifactPath ${rowColor}">\r
-\r
+    \r
 <div class="controls">\r
     <%-- TODO: make some icons --%>\r
   <redback:ifAnyAuthorized permissions="archiva-manage-configuration">\r
     <s:token/>\r
-    <s:url id="deleteLegacyArtifactPath" action="deleteLegacyArtifactPath">\r
+    <s:url id="deleteLegacyArtifactPath" encode="true" action="deleteLegacyArtifactPath">\r
       <s:param name="path" value="%{#attr.legacyArtifactPath.path}"/>\r
       <s:param name="struts.token.name">struts.token</s:param>\r
       <s:param name="struts.token"><s:property value="struts.token"/></s:param>\r
   </redback:ifAnyAuthorized>\r
 </div>\r
 \r
+<%-- used c:out in displaying EL's so that they would be escaped --%>\r
 <table class="infoTable">\r
 <tr>\r
   <th>Path</th>\r
   <td>\r
-    <code>${legacyArtifactPath.path}</code>\r
+    <code><c:out value="${legacyArtifactPath.path}" /></code>\r
   </td>\r
 </tr>\r
 <tr>\r
   <th>Artifact</th>\r
   <td>\r
-    <code>${legacyArtifactPath.artifact}</code>\r
+    <code><c:out value="${legacyArtifactPath.artifact}" /></code>\r
   </td>\r
 </tr>\r
 </table>\r
index 33aec91c5d3288cca3989a1c74632be9de7a245f..1f0b9b658404daded96737fa6591f5900e255e97 100644 (file)
 
 <div id="contentArea">
 
-<s:actionerror /> <s:actionmessage />
+  <%-- changed the structure of displaying errorMessages & actionMessages in order for them to be escaped. --%>
+  <s:if test="hasActionErrors()">
+      <ul>
+      <s:iterator value="actionErrors">
+          <li><span class="errorMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
+  <s:if test="hasActionMessages()">
+      <ul>
+      <s:iterator value="actionMessages">
+          <li><span class="actionMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
 
 <div class="admin">
 <div class="controls">
       <redback:ifAnyAuthorized
         permissions="archiva-manage-configuration">
         <s:token/>
-        <s:url id="editNetworkProxyUrl" action="editNetworkProxy">
+        <s:url id="editNetworkProxyUrl" encode="true" action="editNetworkProxy">
           <s:param name="proxyid" value="%{#attr.proxy.id}" />
         </s:url>
-        <s:url id="deleteNetworkProxyUrl" action="deleteNetworkProxy" method="confirm">
+        <s:url id="deleteNetworkProxyUrl" encode="true" action="deleteNetworkProxy" method="confirm">
           <s:param name="proxyid" value="%{#attr.proxy.id}" />
           <s:param name="struts.token.name">struts.token</s:param>
           <s:param name="struts.token"><s:property value="struts.token"/></s:param>
             Delete Network Proxy</s:a>
       </redback:ifAnyAuthorized></div>
 
+      <%-- used c:out in displaying EL's for them to be escaped.  --%>
       <table class="infoTable">
         <tr>
           <th>Identifier</th>
-          <td><code>${proxy.id}</code></td>
+          <td><code><c:out value="${proxy.id}" /></code></td>
         </tr>
         <tr>
           <th>Protocol</th>
-          <td>${proxy.protocol}</td>
+          <td><c:out value="${proxy.protocol}" /></td>
         </tr>
         <tr>
           <th>Host</th>
-          <td>${proxy.host}</td>
+          <td><c:out value="${proxy.host}" /></td>
         </tr>
         <tr>
           <th>Port</th>
-          <td>${proxy.port}</td>
+          <td><c:out value="${proxy.port}" /></td>
         </tr>
         <c:if test="${not empty (proxy.username)}">
           <tr>
             <th>Username</th>
-            <td>${proxy.username}</td>
+            <td><c:out value="${proxy.username}" /></td>
           </tr>
           <c:if test="${not empty (proxy.password)}">
             <tr>
index 8050fc39f0209e66bb366c200d550bd7c0c0d1d7..dd34ffb80560a01b82dc9866fe22712eb8e62f74 100644 (file)
 
 <div id="contentArea">
 
-<s:actionerror/>
-<s:actionmessage/>
+  <%-- changed the structure of displaying errorMessages & actionMessages in order for them to be escaped. --%>
+  <s:if test="hasActionErrors()">
+      <ul>
+      <s:iterator value="actionErrors">
+          <li><span class="errorMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
+  <s:actionmessage />
+  <s:if test="hasActionMessages()">
+      <ul>
+      <s:iterator value="actionMessages">
+          <li><span class="actionMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
 
 <div class="admin">
 <div class="controls">
 <div class="controls">
     <%-- TODO: make some icons --%>
   <redback:ifAnyAuthorized permissions="archiva-manage-configuration">
-    <s:url id="editRepositoryUrl" action="editRepository">
+      <s:url id="editRepositoryUrl" encode="true" action="editRepository">
       <s:param name="repoid" value="%{#attr.repository.id}"/>
     </s:url>
     <s:token/>
-    <s:url id="deleteRepositoryUrl" action="confirmDeleteRepository">
+    <s:url id="deleteRepositoryUrl" encode="true" action="confirmDeleteRepository">
       <s:param name="repoid" value="%{#attr.repository.id}"/>
       <s:param name="struts.token.name">struts.token</s:param>
       <s:param name="struts.token"><s:property value="struts.token"/></s:param>
     </s:a>
   </redback:ifAnyAuthorized>
   <c:url var="rssFeedIconUrl" value="/images/icons/rss-feed.png"/>
-  <a href="/archiva/feeds/${repository.id}">
+  <a href='/archiva/feeds/<c:out value="${repository.id}" />'>
        <img src="${rssFeedIconUrl}" />
   </a>
 </div>
 
+<%-- used c:out in displaying EL's for them to be escaped.  --%>
 <div style="float: left">
   <img src="<c:url value="/images/archiva-splat-32.gif"/>" alt="" width="32" height="32"/>
 </div>
 
-<h3 class="repository">${repository.name}</h3>
+<h3 class="repository"><c:out value="${repository.name}" /></h3>
 
 <table class="infoTable">
 <tr>
   <th>Identifier</th>
   <td>
-    <code>${repository.id}</code>
+    <code><c:out value="${repository.id}" /></code>
   </td>
 </tr>
 <tr>
   <th>Name</th>
   <td>
-    <code>${repository.name}</code>
+    <code><c:out value="${repository.name}" /></code>
   </td>
 </tr>
 <tr>
   <th>Directory</th>
-  <td>${repository.location}</td>
+  <td><c:out value="${repository.location}" /></td>
 </tr>
 <c:if test="${!empty (repository.indexDir)}">
        <tr>
          <th>Index Directory</th>
-         <td>${repository.indexDir}</td>
+         <td><c:out value="${repository.indexDir}" /></td>
        </tr>
 </c:if>
 <tr>
   <th>WebDAV URL</th>
-  <td><a href="${baseUrl}/${repository.id}/">${baseUrl}/${repository.id}/</a></td>
+  <td><a href='<c:out value="${baseUrl}" />/<c:out value="${repository.id}" />/' ><c:out value="${baseUrl}" />/<c:out value="${repository.id}" />/</a></td>
 </tr>
 <tr>
   <th>Type</th>
     <th>Groups</th>
     <td>
       <c:forEach items="${repositoryToGroupMap[repository.id]}" varStatus="i" var="group">
-        ${group}<c:if test="${!i.last}">,</c:if>        
+        <c:out value="${group}" /><c:if test="${!i.last}">,</c:if>
       </c:forEach>
     </td>
   </tr>
   </tr>
   <tr>
     <th>Repository Purge By Days Older Than</th>
-    <td>${repository.daysOlder}</td>
+    <td><c:out value="${repository.daysOlder}" /></td>
   </tr>
   <tr>
     <th>Repository Purge By Retention Count</th>
-    <td>${repository.retentionCount}</td>
+    <td><c:out value="${repository.retentionCount}" /></td>
   </tr>
 </c:if>
 <tr>
 <c:if test="${repository.scanned}">
   <tr>
     <th>Scanning Cron</th>
-    <td>${repository.refreshCronExpression}</td>
+    <td><c:out value="${repository.refreshCronExpression}" /></td>
   </tr>
   <tr>
     <th>
           <table>
             <tr>
               <th>Last Scanned</th>
-              <td>${stats.whenGathered}</td>
+              <td><c:out value="${stats.whenGathered}" /></td>
             </tr>
             <tr>
               <th>Duration</th>
-              <td>${stats.duration} ms</td>
+              <td><c:out value="${stats.duration}" /> ms</td>
             </tr>
             <tr>
               <th>Total File Count</th>
-              <td>${stats.totalFileCount}
+              <td><c:out value="${stats.totalFileCount}" />
             </tr>
             <tr>
               <th>New Files Found</th>
-              <td>${stats.newFileCount}
+              <td><c:out value="${stats.newFileCount}" />
             </tr>
           </table>
         </c:otherwise>
 
         <div class="controls">
           <redback:ifAnyAuthorized permissions="archiva-manage-configuration">
-            <s:url id="editRepositoryUrl" action="editRemoteRepository">
-              <s:param name="repoid" value="%{#attr.repository.id}"/>
+              <s:url id="editRepositoryUrl" encode="true" action="editRemoteRepository">
+                <s:param name="repoid" value="%{#attr.repository.id}"/>
             </s:url>
             <s:a href="%{editRepositoryUrl}">
               <img src="<c:url value="/images/icons/edit.png" />" alt="" width="16" height="16"/>
               Edit
             </s:a>
             <s:token/>
-            <s:url id="deleteRepositoryUrl" action="confirmDeleteRemoteRepository">
+            <s:url id="deleteRepositoryUrl" encode="true" action="confirmDeleteRemoteRepository">
               <s:param name="repoid" value="%{#attr.repository.id}"/>
               <s:param name="struts.token.name">struts.token</s:param>
               <s:param name="struts.token"><s:property value="struts.token"/></s:param>
           <img src="<c:url value="/images/archiva-world.png"/>" alt="" width="32" height="32"/>
         </div>
 
-        <h3 class="repository">${repository.name}</h3>
+        <h3 class="repository"><c:out value="${repository.name}" /></h3>
 
         <table class="infoTable">
           <tr>
             <th>Identifier</th>
             <td>
-              <code>${repository.id}</code>
+              <code><c:out value="${repository.id}" /></code>
             </td>
           </tr>
           <tr>
             <th>Name</th>
             <td>
-              <code>${repository.name}</code>
+              <code><c:out value="${repository.name}" /></code>
             </td>
           </tr>
           <tr>
             <th>URL</th>
-            <td>${repository.url}</td>
+            <td><c:out value="${repository.url}" /></td>
           </tr>
           <tr>
             <th>Type</th>
index 23fae758a7d8ff3b4c73fd70f3c95f5c2e08a6ce..ec1b77e3ce58947de862856517eec0e411f73ea7 100644 (file)
       <s:set name="organisationUrl" value="organisationUrl"/>
       <c:choose>
         <c:when test="${!empty (organisationUrl)}">
-          <a href="${organisationUrl}">
-            <img src="${organisationLogo}" title="${organisationName}"/>
+          <a href='<c:out value="${organisationUrl}" />'>
+            <img src='<c:out value="${organisationLogo}" />' title='<c:out value="${organisationName}" />'/>
           </a>
         </c:when>
         <c:otherwise>
-          <img src="${organisationLogo}" title="${organisationName}"/>
+          <img src='<c:out value="${organisationLogo}" />' title='<c:out value="${organisationName}" />'/>
         </c:otherwise>
       </c:choose>
     </c:when>
index d518a52d05075356c0996de22896fd9abd04dac8..a742928f5710218f211439240ef0c3f0fe013163 100644 (file)
 <body>
 <h1>Delete Artifact</h1>
 
-  <s:actionerror/>
-  <s:actionmessage/>
+  <%-- changed the structure of displaying errorMessages & actionMessages in order for them to be escaped. --%>
+  <s:if test="hasActionErrors()">
+      <ul>
+      <s:iterator value="actionErrors">
+          <li><span class="errorMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
+  <s:if test="hasActionMessages()">
+      <ul>
+      <s:iterator value="actionMessages">
+          <li><span class="actionMessage"><s:property escape="true" /></span></li>
+      </s:iterator>
+      </ul>
+  </s:if>
 
   <div id="contentArea">
     <s:form action="deleteArtifact!doDelete" namespace="/" method="post" validate="true">    
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/DeleteArtifactActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/DeleteArtifactActionTest.java
new file mode 100644 (file)
index 0000000..9e5a3ae
--- /dev/null
@@ -0,0 +1,188 @@
+package org.apache.maven.archiva.web.action;
+
+/*
+ * 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 com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.validator.ActionValidatorManager;
+import com.opensymphony.xwork2.validator.ActionValidatorManagerFactory;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import junit.framework.TestCase;
+import org.apache.maven.archiva.web.validator.utils.ValidatorUtil;
+
+public class DeleteArtifactActionTest extends TestCase
+{
+    private static final String EMPTY_STRING = "";
+
+    // valid inputs
+    private static final String GROUP_ID_VALID_INPUT = "abcXYZ0129._-";
+
+    private static final String ARTIFACT_ID_VALID_INPUT = "abcXYZ0129._-";
+
+    private static final String VERSION_VALID_INPUT = "1.2.3";
+
+    private static final String REPOSITORY_ID_VALID_INPUT = "abcXYZ0129._-";
+
+    // invalid inputs
+    private static final String GROUP_ID_INVALID_INPUT = "<> \\/~+[ ]'\"";
+
+    private static final String ARTIFACT_ID_INVALID_INPUT = "<> \\/~+[ ]'\"";
+
+    private static final String VERSION_INVALID_INPUT = "<>";
+
+    private static final String REPOSITORY_ID_INVALID_INPUT = "<> \\/~+[ ]'\"";
+
+    // testing requisite
+    private DeleteArtifactAction deleteArtifactAction;
+
+    private ActionValidatorManager actionValidatorManager;
+
+    @Override
+    public void setUp() throws Exception
+    {
+        deleteArtifactAction = new DeleteArtifactAction();
+        ObjectFactory.setObjectFactory(new ObjectFactory());
+        actionValidatorManager = ActionValidatorManagerFactory.getInstance();
+    }
+
+    public void testStruts2ValidationFrameworkWithNullInputs() throws Exception
+    {
+        // prep
+        populateDeleteArtifactActionFields(deleteArtifactAction, null, null, null, null);
+
+        // test
+        actionValidatorManager.validate(deleteArtifactAction, EMPTY_STRING);
+
+        // verify
+        assertTrue(deleteArtifactAction.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = deleteArtifactAction.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a groupId.");
+        expectedFieldErrors.put("groupId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter an artifactId.");
+        expectedFieldErrors.put("artifactId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a version.");
+        expectedFieldErrors.put("version", expectedErrorMessages);
+
+        // repositoryId is not required.
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithBlankInputs() throws Exception
+    {
+        // prep
+        populateDeleteArtifactActionFields(deleteArtifactAction, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING);
+
+        // test
+        actionValidatorManager.validate(deleteArtifactAction, EMPTY_STRING);
+
+        // verify
+        assertTrue(deleteArtifactAction.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = deleteArtifactAction.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a groupId.");
+        expectedFieldErrors.put("groupId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter an artifactId.");
+        expectedFieldErrors.put("artifactId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a version.");
+        expectedFieldErrors.put("version", expectedErrorMessages);
+
+        // repositoryId is not required.
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithInvalidInputs() throws Exception
+    {
+        // prep
+        populateDeleteArtifactActionFields(deleteArtifactAction, GROUP_ID_INVALID_INPUT, ARTIFACT_ID_INVALID_INPUT, VERSION_INVALID_INPUT, REPOSITORY_ID_INVALID_INPUT);
+
+        // test
+        actionValidatorManager.validate(deleteArtifactAction, EMPTY_STRING);
+
+        // verify
+        assertTrue(deleteArtifactAction.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = deleteArtifactAction.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("groupId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("artifactId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Repository id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("repositoryId", expectedErrorMessages);
+
+        // version has its validation in the validate() method of the action class.
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithValidInputs() throws Exception
+    {
+        // prep
+        populateDeleteArtifactActionFields(deleteArtifactAction, GROUP_ID_VALID_INPUT, ARTIFACT_ID_VALID_INPUT, VERSION_VALID_INPUT, REPOSITORY_ID_VALID_INPUT);
+
+        // test
+        actionValidatorManager.validate(deleteArtifactAction, EMPTY_STRING);
+
+        // verify
+        assertFalse(deleteArtifactAction.hasFieldErrors());
+    }
+
+    private void populateDeleteArtifactActionFields(DeleteArtifactAction deleteArtifactAction, String groupId, String artifactId, String version, String repositoryId)
+    {
+        deleteArtifactAction.setGroupId(groupId);
+        deleteArtifactAction.setArtifactId(artifactId);
+        deleteArtifactAction.setVersion(version);
+        deleteArtifactAction.setRepositoryId(repositoryId);
+    }
+}
index e076261a837a7273c730b5e51f0955da4cadc0bd..2b054a0001b12b2cfda70977a96f4c819400141b 100644 (file)
@@ -20,12 +20,47 @@ package org.apache.maven.archiva.web.action.admin.appearance;
  */
 
 import com.opensymphony.xwork2.Action;
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.validator.ActionValidatorManager;
+import com.opensymphony.xwork2.validator.ActionValidatorManagerFactory;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import org.apache.maven.archiva.configuration.OrganisationInformation;
+import org.apache.maven.archiva.web.validator.utils.ValidatorUtil;
 
 /**
  */
 public class EditOrganizationInfoActionTest extends AbstractOrganizationInfoActionTest
 {
+    private static final String EMPTY_STRING = "";
+
+    // valid inputs
+    private static final String ORGANISATION_NAME_VALID_INPUT = "abcXYZ0129.   _/\\~   :?!&=-";
+
+    private static final String ORGANISATION_URL_VALID_INPUT = "file://home/user/abcXYZ0129._/\\~:?!&=-<> ~+[ ]'\"";
+
+    private static final String ORGANISATION_LOGO_VALID_INPUT = "file://home/user/abcXYZ0129._/\\~:?!&=-<> ~+[ ]'\"";
+
+    // invalid inputs
+    private static final String ORGANISATION_NAME_INVALID_INPUT = "<>~+[ ]'\"";
+
+    private static final String ORGANISATION_URL_INVALID_INPUT = "/home/user/abcXYZ0129._/\\~:?!&=-<> ~+[ ]'\"";
+
+    private static final String ORGANISATION_LOGO_INVALID_INPUT = "/home/user/abcXYZ0129._/\\~:?!&=-<> ~+[ ]'\"";
+
+    // testing requisite
+    private ActionValidatorManager actionValidatorManager;
+
+    @Override
+    public void setUp() throws Exception
+    {
+        super.setUp();
+        ObjectFactory.setObjectFactory(new ObjectFactory());
+        actionValidatorManager = ActionValidatorManagerFactory.getInstance();
+    }
+
     public void testOrganisationInfoSaves()
         throws Exception
     {
@@ -56,6 +91,109 @@ public class EditOrganizationInfoActionTest extends AbstractOrganizationInfoActi
         assertEquals("URL1", orginfo.getUrl());
     }
 
+    public void testStruts2ValidationFrameworkWithNullInputs() throws Exception
+    {
+        // prep
+        action = getAction();
+        populateOrganisationValues(action, null, null, null);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertTrue(action.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = action.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a name");
+        expectedFieldErrors.put("organisationName", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithBlankInputs() throws Exception
+    {
+        // prep
+        action = getAction();
+        populateOrganisationValues(action, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertTrue(action.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = action.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a name");
+        expectedFieldErrors.put("organisationName", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithInvalidInputs() throws Exception
+    {
+        // prep
+        action = getAction();
+        populateOrganisationValues(action, ORGANISATION_NAME_INVALID_INPUT, ORGANISATION_URL_INVALID_INPUT, ORGANISATION_LOGO_INVALID_INPUT);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertTrue(action.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = action.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Organisation name must only contain alphanumeric characters, white-spaces(' '), equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).");
+        expectedFieldErrors.put("organisationName", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a URL");
+        expectedFieldErrors.put("organisationUrl", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a URL");
+        expectedFieldErrors.put("organisationLogo", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithValidInputs() throws Exception
+    {
+        // prep
+        action = getAction();
+        populateOrganisationValues(action, ORGANISATION_NAME_VALID_INPUT, ORGANISATION_URL_VALID_INPUT, ORGANISATION_LOGO_VALID_INPUT);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertFalse(action.hasFieldErrors());
+    }
+
+    private void populateOrganisationValues(AbstractAppearanceAction abstractAppearanceAction , String name, String url, String logo)
+    {
+        abstractAppearanceAction.setOrganisationName(name);
+        abstractAppearanceAction.setOrganisationUrl(url);
+        abstractAppearanceAction.setOrganisationLogo(logo);
+    }
+
     @Override
     protected AbstractAppearanceAction getAction() 
     {
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/legacy/AddLegacyArtifactPathActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/legacy/AddLegacyArtifactPathActionTest.java
new file mode 100644 (file)
index 0000000..0a10f15
--- /dev/null
@@ -0,0 +1,232 @@
+package org.apache.maven.archiva.web.action.admin.legacy;
+
+/*
+ * 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 com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.validator.ActionValidatorManager;
+import com.opensymphony.xwork2.validator.ActionValidatorManagerFactory;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import junit.framework.TestCase;
+import org.apache.maven.archiva.configuration.LegacyArtifactPath;
+import org.apache.maven.archiva.web.validator.utils.ValidatorUtil;
+
+public class AddLegacyArtifactPathActionTest extends TestCase
+{
+    private static final String EMPTY_STRING = "";
+
+    // valid inputs
+    private static final String LEGACY_ARTIFACT_PATH_PATH_VALID_INPUT = "-abcXYZ0129._/\\";
+
+    private static final String GROUP_ID_VALID_INPUT = "abcXYZ0129._-";
+
+    private static final String ARTIFACT_ID_VALID_INPUT = "abcXYZ0129._-";
+
+    private static final String VERSION_VALID_INPUT = "abcXYZ0129._-";
+
+    private static final String CLASSIFIER_VALID_INPUT = "abcXYZ0129._-";
+
+    private static final String TYPE_VALID_INPUT = "abcXYZ0129._-";
+
+    // invalid inputs
+    private static final String LEGACY_ARTIFACT_PATH_PATH_INVALID_INPUT = "<> ~+[ ]'\"";
+
+    private static final String GROUP_ID_INVALID_INPUT = "<> \\/~+[ ]'\"";
+
+    private static final String ARTIFACT_ID_INVALID_INPUT = "<> \\/~+[ ]'\"";
+
+    private static final String VERSION_INVALID_INPUT = "<> \\/~+[ ]'\"";
+
+    private static final String CLASSIFIER_INVALID_INPUT = "<> \\/~+[ ]'\"";
+
+    private static final String TYPE_INVALID_INPUT = "<> \\/~+[ ]'\"";
+
+    // testing requisite
+    private AddLegacyArtifactPathAction addLegacyArtifactPathAction;
+
+    private ActionValidatorManager actionValidatorManager;
+
+    @Override
+    public void setUp() throws Exception
+    {
+        addLegacyArtifactPathAction = new AddLegacyArtifactPathAction();
+        ObjectFactory.setObjectFactory(new ObjectFactory());
+        actionValidatorManager = ActionValidatorManagerFactory.getInstance();
+    }
+
+    public void testStruts2ValidationFrameworkWithNullInputs() throws Exception
+    {
+        // prep
+        LegacyArtifactPath legacyArtifactPath = createLegacyArtifactPath(null);
+        populateAddLegacyArtifactPathActionFields(addLegacyArtifactPathAction, legacyArtifactPath, null, null, null, null, null);
+
+        // test
+        actionValidatorManager.validate(addLegacyArtifactPathAction, EMPTY_STRING);
+
+        // verify
+        assertTrue(addLegacyArtifactPathAction.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = addLegacyArtifactPathAction.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a legacy path.");
+        expectedFieldErrors.put("legacyArtifactPath.path", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a groupId.");
+        expectedFieldErrors.put("groupId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter an artifactId.");
+        expectedFieldErrors.put("artifactId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a version.");
+        expectedFieldErrors.put("version", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a type.");
+        expectedFieldErrors.put("type", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithBlankInputs() throws Exception
+    {
+        // prep
+        LegacyArtifactPath legacyArtifactPath = createLegacyArtifactPath(EMPTY_STRING);
+        populateAddLegacyArtifactPathActionFields(addLegacyArtifactPathAction, legacyArtifactPath, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING);
+
+        // test
+        actionValidatorManager.validate(addLegacyArtifactPathAction, EMPTY_STRING);
+
+        // verify
+        assertTrue(addLegacyArtifactPathAction.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = addLegacyArtifactPathAction.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a legacy path.");
+        expectedFieldErrors.put("legacyArtifactPath.path", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a groupId.");
+        expectedFieldErrors.put("groupId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter an artifactId.");
+        expectedFieldErrors.put("artifactId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a version.");
+        expectedFieldErrors.put("version", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a type.");
+        expectedFieldErrors.put("type", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithInvalidInputs() throws Exception
+    {
+        // prep
+        LegacyArtifactPath legacyArtifactPath = createLegacyArtifactPath(LEGACY_ARTIFACT_PATH_PATH_INVALID_INPUT);
+        populateAddLegacyArtifactPathActionFields(addLegacyArtifactPathAction, legacyArtifactPath, GROUP_ID_INVALID_INPUT, ARTIFACT_ID_INVALID_INPUT, VERSION_INVALID_INPUT, CLASSIFIER_INVALID_INPUT, TYPE_INVALID_INPUT);
+
+        // test
+        actionValidatorManager.validate(addLegacyArtifactPathAction, EMPTY_STRING);
+
+        // verify
+        assertTrue(addLegacyArtifactPathAction.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = addLegacyArtifactPathAction.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Legacy path must only contain alphanumeric characters, forward-slashes(/), back-slashes(\\), underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("legacyArtifactPath.path", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Group id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("groupId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Artifact id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("artifactId", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Version must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("version", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Classifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("classifier", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Type must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("type", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithValidInputs() throws Exception
+    {
+        // prep
+        LegacyArtifactPath legacyArtifactPath = createLegacyArtifactPath(LEGACY_ARTIFACT_PATH_PATH_VALID_INPUT);
+        populateAddLegacyArtifactPathActionFields(addLegacyArtifactPathAction, legacyArtifactPath, GROUP_ID_VALID_INPUT, ARTIFACT_ID_VALID_INPUT, VERSION_VALID_INPUT, CLASSIFIER_VALID_INPUT, TYPE_VALID_INPUT);
+
+        // test
+        actionValidatorManager.validate(addLegacyArtifactPathAction, EMPTY_STRING);
+
+        // verify
+        assertFalse(addLegacyArtifactPathAction.hasFieldErrors());
+    }
+
+    private LegacyArtifactPath createLegacyArtifactPath(String path)
+    {
+        LegacyArtifactPath legacyArtifactPath = new LegacyArtifactPath();
+        legacyArtifactPath.setPath(path);
+        return legacyArtifactPath;
+    }
+
+    private void populateAddLegacyArtifactPathActionFields(AddLegacyArtifactPathAction addLegacyArtifactPathAction, LegacyArtifactPath legacyArtifactPath, String groupId, String artifactId, String version, String classifier, String type)
+    {
+        addLegacyArtifactPathAction.setLegacyArtifactPath(legacyArtifactPath);
+        addLegacyArtifactPathAction.setGroupId(groupId);
+        addLegacyArtifactPathAction.setArtifactId(artifactId);
+        addLegacyArtifactPathAction.setVersion(version);
+        addLegacyArtifactPathAction.setClassifier(classifier);
+        addLegacyArtifactPathAction.setType(type);
+    }
+}
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/networkproxies/ConfigureNetworkProxyActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/networkproxies/ConfigureNetworkProxyActionTest.java
new file mode 100644 (file)
index 0000000..0713739
--- /dev/null
@@ -0,0 +1,216 @@
+package org.apache.maven.archiva.web.action.admin.networkproxies;
+
+/*
+ * 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 com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.validator.ActionValidatorManager;
+import com.opensymphony.xwork2.validator.ActionValidatorManagerFactory;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import junit.framework.TestCase;
+import org.apache.maven.archiva.configuration.NetworkProxyConfiguration;
+import org.apache.maven.archiva.web.validator.utils.ValidatorUtil;
+
+public class ConfigureNetworkProxyActionTest extends TestCase
+{
+    private static final String EMPTY_STRING = "";
+
+    private static final String VALIDATION_CONTEXT = "saveNetworkProxy";
+
+    // valid inputs
+    private static final String PROXY_ID_VALID_INPUT = "abcXYZ0129._-";
+
+    private static final String PROXY_PROTOCOL_VALID_INPUT = "-abcXYZ0129./:\\";
+
+    private static final String PROXY_HOST_VALID_INPUT = "abcXYZ0129._/\\~:?!&=-";
+
+    private static final int PROXY_PORT_VALID_INPUT = 8080;
+
+    private static final String PROXY_USERNAME_VALID_INPUT = "abcXYZ0129.@/_-\\";
+
+    // invalid inputs
+    private static final String PROXY_ID_INVALID_INPUT = "<> \\/~+[ ]'\"";
+
+    private static final String PROXY_PROTOCOL_INVALID_INPUT = "<> ~+[ ]'\"";
+
+    private static final String PROXY_HOST_INVALID_INPUT = "<> ~+[ ]'\"";
+
+    private static final int PROXY_PORT_INVALID_INPUT = 0;
+
+    private static final String PROXY_USERNAME_INVALID_INPUT = "<> ~+[ ]'\"";
+
+    // testing requisite
+    private ConfigureNetworkProxyAction configureNetworkProxyAction;
+
+    private ActionValidatorManager actionValidatorManager;
+    
+    @Override
+    public void setUp()
+    {
+        configureNetworkProxyAction = new ConfigureNetworkProxyAction();
+        ObjectFactory.setObjectFactory(new ObjectFactory());
+        actionValidatorManager = ActionValidatorManagerFactory.getInstance();
+    }
+
+    public void testStruts2ValidationFrameworkWithNullInputs() throws Exception
+    {
+        // prep
+        NetworkProxyConfiguration networkProxyConfiguration = createNetworkProxyConfiguration(null, null, null, null);
+        configureNetworkProxyAction.setProxy(networkProxyConfiguration);
+
+        // test
+        actionValidatorManager.validate(configureNetworkProxyAction, VALIDATION_CONTEXT);
+
+        // verify
+        assertTrue(configureNetworkProxyAction.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = configureNetworkProxyAction.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter an identifier.");
+        expectedFieldErrors.put("proxy.id", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a protocol.");
+        expectedFieldErrors.put("proxy.protocol", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a host.");
+        expectedFieldErrors.put("proxy.host", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithBlankInputs() throws Exception
+    {
+        // prep
+        NetworkProxyConfiguration networkProxyConfiguration = createNetworkProxyConfiguration(EMPTY_STRING, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING);
+        configureNetworkProxyAction.setProxy(networkProxyConfiguration);
+
+        // test
+        actionValidatorManager.validate(configureNetworkProxyAction, VALIDATION_CONTEXT);
+
+        // verify
+        assertTrue(configureNetworkProxyAction.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = configureNetworkProxyAction.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter an identifier.");
+        expectedFieldErrors.put("proxy.id", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a protocol.");
+        expectedFieldErrors.put("proxy.protocol", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a host.");
+        expectedFieldErrors.put("proxy.host", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithInvalidInputs() throws Exception
+    {
+        // prep
+        NetworkProxyConfiguration networkProxyConfiguration = createNetworkProxyConfiguration(PROXY_ID_INVALID_INPUT, PROXY_HOST_INVALID_INPUT, PROXY_PORT_INVALID_INPUT, PROXY_PROTOCOL_INVALID_INPUT, PROXY_USERNAME_INVALID_INPUT);
+        configureNetworkProxyAction.setProxy(networkProxyConfiguration);
+
+        // test
+        actionValidatorManager.validate(configureNetworkProxyAction, VALIDATION_CONTEXT);
+
+        // verify
+        assertTrue(configureNetworkProxyAction.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = configureNetworkProxyAction.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Proxy id must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("proxy.id", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Protocol must only contain alphanumeric characters, forward-slashes(/), back-slashes(\\), dots(.), colons(:), and dashes(-).");
+        expectedFieldErrors.put("proxy.protocol", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Host must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).");
+        expectedFieldErrors.put("proxy.host", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Port needs to be larger than 1");
+        expectedFieldErrors.put("proxy.port", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Username must only contain alphanumeric characters, at's(@), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("proxy.username", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithValidInputs() throws Exception
+    {
+        // prep
+        NetworkProxyConfiguration networkProxyConfiguration = createNetworkProxyConfiguration(PROXY_ID_VALID_INPUT, PROXY_HOST_VALID_INPUT, PROXY_PORT_VALID_INPUT, PROXY_PROTOCOL_VALID_INPUT, PROXY_USERNAME_VALID_INPUT);
+        configureNetworkProxyAction.setProxy(networkProxyConfiguration);
+
+        // test
+        actionValidatorManager.validate(configureNetworkProxyAction, VALIDATION_CONTEXT);
+
+        // verify
+        assertFalse(configureNetworkProxyAction.hasFieldErrors());
+    }
+
+    private NetworkProxyConfiguration createNetworkProxyConfiguration(String id, String host, int port, String protocol, String username)
+    {
+        NetworkProxyConfiguration networkProxyConfiguration = new NetworkProxyConfiguration();
+        networkProxyConfiguration.setId(id);
+        networkProxyConfiguration.setHost(host);
+        networkProxyConfiguration.setPort(port);
+        networkProxyConfiguration.setProtocol(protocol);
+        networkProxyConfiguration.setUsername(username);
+        return networkProxyConfiguration;
+    }
+
+    // over-loaded
+    // for simulating empty/null form purposes; excluding primitive data-typed values
+    private NetworkProxyConfiguration createNetworkProxyConfiguration(String id, String host, String protocol, String username)
+    {
+        NetworkProxyConfiguration networkProxyConfiguration = new NetworkProxyConfiguration();
+        networkProxyConfiguration.setId(id);
+        networkProxyConfiguration.setHost(host);
+        networkProxyConfiguration.setProtocol(protocol);
+        networkProxyConfiguration.setUsername(username);
+        return networkProxyConfiguration;
+    }
+}
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/AbstractManagedRepositoryActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/AbstractManagedRepositoryActionTest.java
new file mode 100644 (file)
index 0000000..8e2085d
--- /dev/null
@@ -0,0 +1,117 @@
+package org.apache.maven.archiva.web.action.admin.repositories;
+
+/*
+ * 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 com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.validator.ActionValidatorManager;
+import com.opensymphony.xwork2.validator.ActionValidatorManagerFactory;
+import java.io.File;
+import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
+import org.codehaus.plexus.spring.PlexusInSpringTestCase;
+
+public abstract class AbstractManagedRepositoryActionTest extends PlexusInSpringTestCase
+{
+    protected static final String EMPTY_STRING = "";
+
+    // valid inputs; validation testing
+    protected static final String REPOSITORY_ID_VALID_INPUT = "abcXYZ0129._-";
+
+    protected static final String REPOSITORY_LOCATION_VALID_INPUT = "abcXYZ0129._/\\~:?!&=-";
+
+    protected static final String REPOSITORY_INDEX_DIR_VALID_INPUT = "abcXYZ0129._/\\~:?!&=-";
+
+    protected static final String REPOSITORY_NAME_VALID_INPUT = "abcXYZ   0129.)/   _(-";
+
+    protected static final int REPOSITORY_RETENTION_COUNT_VALID_INPUT = 1;
+
+    protected static final int REPOSITORY_DAYS_OLDER_VALID_INPUT = 1;
+
+    // invalid inputs; validation testing
+    protected static final String REPOSITORY_ID_INVALID_INPUT = "<> \\/~+[ ]'\"";
+
+    protected static final String REPOSITORY_LOCATION_INVALID_INPUT = "<> ~+[ ]'\"";
+
+    protected static final String REPOSITORY_INDEX_DIR_INVALID_INPUT = "<> ~+[ ]'\"";
+
+    protected static final String REPOSITORY_NAME_INVALID_INPUT = "<>\\~+[]'\"";
+
+    protected static final int REPOSITORY_RETENTION_COUNT_INVALID_INPUT = 101;
+
+    protected static final int REPOSITORY_DAYS_OLDER_INVALID_INPUT = -1;
+
+    // testing requisite; validation testing
+    protected ActionValidatorManager actionValidatorManager;
+
+    protected static final String REPO_ID = "repo-ident";
+
+    protected File location;
+
+    @Override
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+
+        ObjectFactory.setObjectFactory(new ObjectFactory());
+        actionValidatorManager = ActionValidatorManagerFactory.getInstance();
+    }
+
+    protected void populateRepository( ManagedRepositoryConfiguration repository )
+    {
+        repository.setId( REPO_ID );
+        repository.setName( "repo name" );
+        repository.setLocation( location.getAbsolutePath() );
+        repository.setLayout( "default" );
+        repository.setRefreshCronExpression( "* 0/5 * * * ?" );
+        repository.setDaysOlder( 31 );
+        repository.setRetentionCount( 20 );
+        repository.setReleases( true );
+        repository.setSnapshots( true );
+        repository.setScanned( false );
+        repository.setDeleteReleasedSnapshots( true );
+    }
+
+    protected ManagedRepositoryConfiguration createManagedRepositoryConfiguration(String id, String name, String location, String indexDir, int daysOlder, int retentionCount)
+    {
+        ManagedRepositoryConfiguration managedRepositoryConfiguration = new ManagedRepositoryConfiguration();
+
+        managedRepositoryConfiguration.setId(id);
+        managedRepositoryConfiguration.setName(name);
+        managedRepositoryConfiguration.setLocation(location);
+        managedRepositoryConfiguration.setIndexDir(indexDir);
+        managedRepositoryConfiguration.setDaysOlder(daysOlder);
+        managedRepositoryConfiguration.setRetentionCount(retentionCount);
+
+        return managedRepositoryConfiguration;
+    }
+
+    // over-loaded
+    // for simulating empty/null form purposes; excluding primitive data-typed values
+    protected ManagedRepositoryConfiguration createManagedRepositoryConfiguration(String id, String name, String location, String indexDir)
+    {
+        ManagedRepositoryConfiguration managedRepositoryConfiguration = new ManagedRepositoryConfiguration();
+
+        managedRepositoryConfiguration.setId(id);
+        managedRepositoryConfiguration.setName(name);
+        managedRepositoryConfiguration.setLocation(location);
+        managedRepositoryConfiguration.setIndexDir(indexDir);
+
+        return managedRepositoryConfiguration;
+    }
+}
index 7accb4b7cf76ad9ad7caca4902b09996fce6b1ec..e6b613a4a1f47e25bce4dd9fd12979bcac7587e7 100644 (file)
@@ -30,11 +30,14 @@ import org.apache.maven.archiva.security.ArchivaRoleConstants;
 import org.codehaus.plexus.redback.role.RoleManager;
 import org.codehaus.redback.integration.interceptor.SecureActionBundle;
 import org.codehaus.redback.integration.interceptor.SecureActionException;
-import org.codehaus.plexus.spring.PlexusInSpringTestCase;
 import org.easymock.MockControl;
 
-import java.io.File;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.maven.archiva.web.validator.utils.ValidatorUtil;
 
 /**
  * AddManagedRepositoryActionTest 
@@ -42,7 +45,7 @@ import java.util.Collections;
  * @version $Id$
  */
 public class AddManagedRepositoryActionTest
-    extends PlexusInSpringTestCase
+    extends AbstractManagedRepositoryActionTest
 {
     private AddManagedRepositoryAction action;
 
@@ -57,10 +60,6 @@ public class AddManagedRepositoryActionTest
     private ArchivaAuditLogsDao auditLogsDao;
 
     private MockControl auditLogsDaoControl;
-
-    private static final String REPO_ID = "repo-ident";
-
-    private File location;
     
     @Override
     protected String getPlexusConfigLocation()
@@ -190,20 +189,131 @@ public class AddManagedRepositoryActionTest
         String status = action.commit();
         assertEquals( AddManagedRepositoryAction.CONFIRM, status );
     }
-    
-    private void populateRepository( ManagedRepositoryConfiguration repository )
+
+    public void testStruts2ValidationFrameworkWithNullInputs() throws Exception
+    {
+        // prep
+        // 0 is the default value for primitive int; null for objects
+        ManagedRepositoryConfiguration managedRepositoryConfiguration = createManagedRepositoryConfiguration(null, null, null, null);
+        action.setRepository(managedRepositoryConfiguration);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertTrue(action.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = action.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a repository identifier.");
+        expectedFieldErrors.put("repository.id", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a directory.");
+        expectedFieldErrors.put("repository.location", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a repository name.");
+        expectedFieldErrors.put("repository.name", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithBlankInputs() throws Exception
+    {
+        // prep
+        // 0 is the default value for primitive int
+        ManagedRepositoryConfiguration managedRepositoryConfiguration = createManagedRepositoryConfiguration(EMPTY_STRING, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING);
+        action.setRepository(managedRepositoryConfiguration);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertTrue(action.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = action.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a repository identifier.");
+        expectedFieldErrors.put("repository.id", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a directory.");
+        expectedFieldErrors.put("repository.location", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a repository name.");
+        expectedFieldErrors.put("repository.name", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithInvalidInputs() throws Exception
     {
-        repository.setId( REPO_ID );
-        repository.setName( "repo name" );
-        repository.setLocation( location.getAbsolutePath() );
-        repository.setLayout( "default" );
-        repository.setRefreshCronExpression( "* 0/5 * * * ?" );
-        repository.setDaysOlder( 31 );
-        repository.setRetentionCount( 20 );
-        repository.setReleases( true );
-        repository.setSnapshots( true );
-        repository.setScanned( false );
-        repository.setDeleteReleasedSnapshots( true );
+        // prep
+        ManagedRepositoryConfiguration managedRepositoryConfiguration = createManagedRepositoryConfiguration(REPOSITORY_ID_INVALID_INPUT, REPOSITORY_NAME_INVALID_INPUT, REPOSITORY_LOCATION_INVALID_INPUT, REPOSITORY_INDEX_DIR_INVALID_INPUT, REPOSITORY_DAYS_OLDER_INVALID_INPUT, REPOSITORY_RETENTION_COUNT_INVALID_INPUT);
+        action.setRepository(managedRepositoryConfiguration);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertTrue(action.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = action.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Identifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("repository.id", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).");
+        expectedFieldErrors.put("repository.location", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Repository Name must only contain alphanumeric characters, white-spaces(' '), forward-slashes(/), open-parenthesis('('), close-parenthesis(')'),  underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("repository.name", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Index directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).");
+        expectedFieldErrors.put("repository.indexDir", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Repository Purge By Retention Count needs to be between 1 and 100.");
+        expectedFieldErrors.put("repository.retentionCount", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Repository Purge By Days Older Than needs to be larger than 0.");
+        expectedFieldErrors.put("repository.daysOlder", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithValidInputs() throws Exception
+    {
+        // prep
+        ManagedRepositoryConfiguration managedRepositoryConfiguration = createManagedRepositoryConfiguration(REPOSITORY_ID_VALID_INPUT, REPOSITORY_NAME_VALID_INPUT, REPOSITORY_LOCATION_VALID_INPUT, REPOSITORY_INDEX_DIR_VALID_INPUT, REPOSITORY_DAYS_OLDER_VALID_INPUT, REPOSITORY_RETENTION_COUNT_VALID_INPUT);
+        action.setRepository(managedRepositoryConfiguration);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertFalse(action.hasFieldErrors());
     }
 
     // TODO: test errors during add, other actions
index 6f9bdf16246b0b49253eb16eda53c6d3dffd705d..89b8ee57c44b9bd1e41d8632dbc78f666fa83f58 100644 (file)
@@ -20,6 +20,9 @@ package org.apache.maven.archiva.web.action.admin.repositories;
  */
 
 import com.opensymphony.xwork2.Action;
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.validator.ActionValidatorManager;
+import com.opensymphony.xwork2.validator.ActionValidatorManagerFactory;
 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
 import org.apache.maven.archiva.configuration.Configuration;
 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
@@ -41,7 +44,10 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import org.apache.maven.archiva.web.validator.utils.ValidatorUtil;
 
 /**
  * EditManagedRepositoryActionTest 
@@ -49,7 +55,7 @@ import java.util.List;
  * @version $Id$
  */
 public class EditManagedRepositoryActionTest
-    extends PlexusInSpringTestCase
+    extends AbstractManagedRepositoryActionTest
 {
     private EditManagedRepositoryAction action;
 
@@ -73,16 +79,13 @@ public class EditManagedRepositoryActionTest
 
     private MockControl auditLogsDaoControl;
 
-    private static final String REPO_ID = "repo-ident";
-
-    private File location;
-
     @Override
     protected String getPlexusConfigLocation()
     {
         return AbstractManagedRepositoriesAction.class.getName().replace( '.', '/' ) + "Test.xml";
     }
-    
+
+    @Override
     protected void setUp()
         throws Exception
     {
@@ -258,6 +261,132 @@ public class EditManagedRepositoryActionTest
         repoContentStatsDaoControl.verify();
         auditLogsDaoControl.verify();
     }
+
+    public void testStruts2ValidationFrameworkWithNullInputs() throws Exception
+    {
+        // prep
+        // 0 is the default value for primitive int; null for objects
+        ManagedRepositoryConfiguration managedRepositoryConfiguration = createManagedRepositoryConfiguration(null, null, null, null);
+        action.setRepository(managedRepositoryConfiguration);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertTrue(action.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = action.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a repository identifier.");
+        expectedFieldErrors.put("repository.id", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a directory.");
+        expectedFieldErrors.put("repository.location", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a repository name.");
+        expectedFieldErrors.put("repository.name", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithBlankInputs() throws Exception
+    {
+        // prep
+        // 0 is the default value for primitive int
+        ManagedRepositoryConfiguration managedRepositoryConfiguration = createManagedRepositoryConfiguration(EMPTY_STRING, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING);
+        action.setRepository(managedRepositoryConfiguration);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertTrue(action.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = action.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a repository identifier.");
+        expectedFieldErrors.put("repository.id", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a directory.");
+        expectedFieldErrors.put("repository.location", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("You must enter a repository name.");
+        expectedFieldErrors.put("repository.name", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithInvalidInputs() throws Exception
+    {
+        // prep
+        ManagedRepositoryConfiguration managedRepositoryConfiguration = createManagedRepositoryConfiguration(REPOSITORY_ID_INVALID_INPUT, REPOSITORY_NAME_INVALID_INPUT, REPOSITORY_LOCATION_INVALID_INPUT, REPOSITORY_INDEX_DIR_INVALID_INPUT, REPOSITORY_DAYS_OLDER_INVALID_INPUT, REPOSITORY_RETENTION_COUNT_INVALID_INPUT);
+        action.setRepository(managedRepositoryConfiguration);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertTrue(action.hasFieldErrors());
+
+        Map<String, List<String>> fieldErrors = action.getFieldErrors();
+
+        // make an expected field error object
+        Map<String, List<String>> expectedFieldErrors = new HashMap<String, List<String>>();
+
+        // populate
+        List<String> expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Identifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("repository.id", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).");
+        expectedFieldErrors.put("repository.location", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Repository Name must only contain alphanumeric characters, white-spaces(' '), forward-slashes(/), open-parenthesis('('), close-parenthesis(')'),  underscores(_), dots(.), and dashes(-).");
+        expectedFieldErrors.put("repository.name", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Index directory must only contain alphanumeric characters, equals(=), question-marks(?), exclamation-points(!), ampersands(&), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-).");
+        expectedFieldErrors.put("repository.indexDir", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Repository Purge By Retention Count needs to be between 1 and 100.");
+        expectedFieldErrors.put("repository.retentionCount", expectedErrorMessages);
+
+        expectedErrorMessages = new ArrayList<String>();
+        expectedErrorMessages.add("Repository Purge By Days Older Than needs to be larger than 0.");
+        expectedFieldErrors.put("repository.daysOlder", expectedErrorMessages);
+
+        ValidatorUtil.assertFieldErrors(expectedFieldErrors, fieldErrors);
+    }
+
+    public void testStruts2ValidationFrameworkWithValidInputs() throws Exception
+    {
+        // prep
+        ManagedRepositoryConfiguration managedRepositoryConfiguration = createManagedRepositoryConfiguration(REPOSITORY_ID_VALID_INPUT, REPOSITORY_NAME_VALID_INPUT, REPOSITORY_LOCATION_VALID_INPUT, REPOSITORY_INDEX_DIR_VALID_INPUT, REPOSITORY_DAYS_OLDER_VALID_INPUT, REPOSITORY_RETENTION_COUNT_VALID_INPUT);
+        action.setRepository(managedRepositoryConfiguration);
+
+        // test
+        actionValidatorManager.validate(action, EMPTY_STRING);
+
+        // verify
+        assertFalse(action.hasFieldErrors());
+    }
     
     private void assertRepositoryEquals( ManagedRepositoryConfiguration expectedRepository,
                                          ManagedRepositoryConfiguration actualRepository )
@@ -292,22 +421,6 @@ public class EditManagedRepositoryActionTest
         return r;
     }
 
-    private void populateRepository( ManagedRepositoryConfiguration repository )
-        throws IOException
-    {
-        repository.setId( REPO_ID );
-        repository.setName( "repo name" );
-        repository.setLocation( location.getCanonicalPath() );
-        repository.setLayout( "default" );
-        repository.setRefreshCronExpression( "* 0/5 * * * ?" );
-        repository.setDaysOlder( 31 );
-        repository.setRetentionCount( 20 );
-        repository.setReleases( true );
-        repository.setSnapshots( true );
-        repository.setScanned( false );
-        repository.setDeleteReleasedSnapshots( true );
-    }
-
     private List<RepositoryContentStatistics> createRepositoryContentStatisticsList()
     {
         List<RepositoryContentStatistics> repoStatsList = new ArrayList<RepositoryContentStatistics>();
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/validator/utils/ValidatorUtil.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/validator/utils/ValidatorUtil.java
new file mode 100644 (file)
index 0000000..a02301e
--- /dev/null
@@ -0,0 +1,62 @@
+package org.apache.maven.archiva.web.validator.utils;
+
+/*
+ * 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.util.List;
+import java.util.Map;
+import junit.framework.Assert;
+
+public class ValidatorUtil
+{
+    public static void assertFieldErrors(Map<String, List<String>> expectedFieldErrors, Map<String, List<String>> actualFieldErrors)
+    {
+        if(expectedFieldErrors != null)
+        {
+            Assert.assertNotNull(actualFieldErrors);
+            // checks the number of field errors
+            Assert.assertEquals(expectedFieldErrors.size(), actualFieldErrors.size());
+
+            // check every content of the field error
+            for(Map.Entry<String, List<String>> expectedEntry : expectedFieldErrors.entrySet())
+            {
+                if(expectedEntry.getValue() != null)
+                {
+                    Assert.assertNotNull(actualFieldErrors.get(expectedEntry.getKey()));
+                    // checks the error message count per error field
+                    Assert.assertEquals(expectedEntry.getValue().size(), actualFieldErrors.get(expectedEntry.getKey()).size());
+
+                    // check the contents of error messages per field error
+                    for(int i = 0; i < expectedEntry.getValue().size(); i++)
+                    {
+                        Assert.assertEquals(expectedEntry.getValue().get(i), actualFieldErrors.get(expectedEntry.getKey()).get(i));
+                    }
+                }
+                else
+                {
+                    Assert.assertNull(actualFieldErrors.get(expectedEntry.getKey()));
+                }
+            }
+        }
+        else
+        {
+            Assert.assertNull(actualFieldErrors);
+        }
+    }
+}