From b44ad982c3afa5a3f34c4fd682eea9b2925e7898 Mon Sep 17 00:00:00 2001 From: "Maria Odea B. Ching" Date: Mon, 11 Jan 2010 15:07:00 +0000 Subject: [PATCH] [MRM-1296] Audit logging report merged MRM-1296 branch to trunk git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@897892 13f79535-47bb-0310-9956-ffa450edef68 --- .../site/apt/userguide/auditlog-report.apt | 38 ++ archiva-docs/src/site/apt/userguide/index.apt | 2 + .../site/resources/images/latest-events.png | Bin 0 -> 72218 bytes archiva-docs/src/site/site.xml | 1 + .../archiva-base/archiva-model/pom.xml | 2 +- .../src/main/mdo/archiva-base.xml | 75 ++- .../archiva/database/ArchivaAuditLogsDao.java | 35 ++ .../ArchivaAuditLogsConstraint.java | 106 +++++ .../MostRecentArchivaAuditLogsConstraint.java | 49 ++ .../maven/archiva/database/jdo/JdoAccess.java | 2 +- .../database/jdo/JdoArchivaAuditLogsDao.java | 62 +++ .../security/ArchivaRoleConstants.java | 2 + .../resources/META-INF/redback/redback.xml | 11 + .../src/test/testng/config/testng.xml | 1 + .../archiva/web/test/AuditLogsReportTest.java | 125 +++++ .../web/action/PlexusActionSupport.java | 22 + .../archiva/web/action/UploadAction.java | 4 +- .../reports/ViewAuditLogReportAction.java | 433 ++++++++++++++++++ .../src/main/resources/struts.xml | 10 + .../webapp/WEB-INF/jsp/decorators/default.jsp | 9 +- .../WEB-INF/jsp/reports/auditLogReport.jsp | 152 ++++++ .../src/main/webapp/css/site.css | 44 +- .../archiva/web/action/UploadActionTest.java | 51 ++- .../DisableProxyConnectorActionTest.java | 2 +- .../AddManagedRepositoryActionTest.java | 18 +- .../repositories/ArchivaAuditLogsDaoStub.java | 34 ++ .../DeleteManagedRepositoryActionTest.java | 34 +- .../EditManagedRepositoryActionTest.java | 23 +- .../archiva/web/action/BrowseActionTest.xml | 5 + .../web/action/ShowArtifactActionTest.xml | 5 + .../EditOrganizationInfoActionTest.xml | 28 ++ .../appearance/OrganizationInfoActionTest.xml | 28 ++ .../proxy/AddProxyConnectorActionTest.xml | 6 +- .../proxy/DeleteProxyConnectorActionTest.xml | 28 ++ .../proxy/DisableProxyConnectorActionTest.xml | 28 ++ .../proxy/EditProxyConnectorActionTest.xml | 8 +- .../proxy/EnableProxyConnectorActionTest.xml | 28 ++ .../proxy/ProxyConnectorsActionTest.xml | 28 ++ .../proxy/SortProxyConnectorsActionTest.xml | 28 ++ .../AbstractManagedRepositoriesActionTest.xml | 8 +- .../AddRemoteRepositoryActionTest.xml | 28 ++ .../DeleteManagedRepositoryActionTest.xml | 7 +- .../DeleteRemoteRepositoryActionTest.xml | 28 ++ .../DeleteRepositoryGroupActionTest.xml | 28 ++ .../EditRemoteRepositoryActionTest.xml | 28 ++ .../repositories/RepositoriesActionTest.xml | 5 + .../RepositoryGroupsActionTest.xml | 28 ++ .../SortRepositoriesActionTest.xml | 28 ++ .../reports/GenerateReportActionTest.xml | 7 +- .../archiva/web/rss/RssFeedServletTest.xml | 5 + .../archiva/webdav/ArchivaDavResource.java | 33 +- .../webdav/ArchivaDavResourceFactory.java | 23 +- .../webdav/ArchivaDavResourceFactoryTest.java | 13 +- .../maven/archiva/webdav/DavResourceTest.java | 42 +- .../webdav/RepositoryServletSecurityTest.java | 6 +- .../webdav/RepositoryServletSecurityTest.xml | 5 + .../archiva/webdav/RepositoryServletTest.xml | 5 + 57 files changed, 1849 insertions(+), 45 deletions(-) create mode 100644 archiva-docs/src/site/apt/userguide/auditlog-report.apt create mode 100644 archiva-docs/src/site/resources/images/latest-events.png create mode 100644 archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/ArchivaAuditLogsDao.java create mode 100644 archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/ArchivaAuditLogsConstraint.java create mode 100644 archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/MostRecentArchivaAuditLogsConstraint.java create mode 100644 archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoArchivaAuditLogsDao.java create mode 100644 archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/AuditLogsReportTest.java create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/reports/ViewAuditLogReportAction.java create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/auditLogReport.jsp create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/ArchivaAuditLogsDaoStub.java create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/appearance/EditOrganizationInfoActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/appearance/OrganizationInfoActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/DeleteProxyConnectorActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/DisableProxyConnectorActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/EnableProxyConnectorActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/ProxyConnectorsActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/SortProxyConnectorsActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/AddRemoteRepositoryActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteRemoteRepositoryActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteRepositoryGroupActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/EditRemoteRepositoryActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/RepositoryGroupsActionTest.xml create mode 100644 archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/SortRepositoriesActionTest.xml diff --git a/archiva-docs/src/site/apt/userguide/auditlog-report.apt b/archiva-docs/src/site/apt/userguide/auditlog-report.apt new file mode 100644 index 000000000..c2eb93cbe --- /dev/null +++ b/archiva-docs/src/site/apt/userguide/auditlog-report.apt @@ -0,0 +1,38 @@ + ------ + Audit Log Report + ------ + +Audit Log Report + + Starting with Archiva 1.3, audit events can be viewed and queried from the web UI. In the current implementation, only artifact upload events are viewable + but there are plans to include other events such as artifact delete, repository creation and deletion, configuration changes, etc. + + To view the audit events, click <<>> from the navigation menu. Initially, the latest 10 artifact upload events are displayed. + +[../images/latest-events.png] Latest Events + +* Customizing the Audit Log Report + + The following fields can be specified when querying for the audit events: + + [[1]] Repository - the repository where the events happened. Only those repositories which the logged in user has permission to access are listed in the drop-down + box. + + [[2]] Group ID - the <<>> of the artifact whose audit events you want to view. + + [[3]] Artifact ID - the <<>> of the artifact whose audit events you want to view. + + [[4]] Start Date - the start date of the event(s) you want to view. This defaults to the current date if none is specified. + + [[5]] End Date - the end date of the event(s) you want to view. This defaults to the current date if none is specified. + + [[6]] Row Count - the number of rows you want displayed per page. This will be the basis for the pagination of the results. The default value is 30 rows. + + [] + + Just specify values for either one or all of the above fields and then submit the form to perform the query. The results of the query will be displayed at the lower + section of the page, similar to that shown in the <<>> except that the heading will be <<>> instead of <<>>. + + + + diff --git a/archiva-docs/src/site/apt/userguide/index.apt b/archiva-docs/src/site/apt/userguide/index.apt index d79e6eb3d..4227e8f46 100644 --- a/archiva-docs/src/site/apt/userguide/index.apt +++ b/archiva-docs/src/site/apt/userguide/index.apt @@ -20,6 +20,8 @@ Users Guide * {{{virtual-repositories.html} Configuring Virtual Repositories}} * {{{rss.html}RSS Feeds in Archiva}} + + * {{{auditlog-report.html}Viewing the Audit Log Report}} [] diff --git a/archiva-docs/src/site/resources/images/latest-events.png b/archiva-docs/src/site/resources/images/latest-events.png new file mode 100644 index 0000000000000000000000000000000000000000..823234031e3fed82f69835c9b3a7831971173452 GIT binary patch literal 72218 zcmd?S2UL~k)-Al%*b9jfQ53L%QUq*>bgZx`B3-&@q)L%0AVrNBQ9(9ML5kA5Nbf2^ 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 LF;Syu{o{WDjs`jA literal 0 HcmV?d00001 diff --git a/archiva-docs/src/site/site.xml b/archiva-docs/src/site/site.xml index ca9eb0e0f..9c6650c2a 100644 --- a/archiva-docs/src/site/site.xml +++ b/archiva-docs/src/site/site.xml @@ -40,6 +40,7 @@ + diff --git a/archiva-modules/archiva-base/archiva-model/pom.xml b/archiva-modules/archiva-base/archiva-model/pom.xml index f686016c9..f24fd3724 100755 --- a/archiva-modules/archiva-base/archiva-model/pom.xml +++ b/archiva-modules/archiva-base/archiva-model/pom.xml @@ -70,7 +70,7 @@ org.codehaus.modello modello-maven-plugin - 1.2.1 + 1.3.0 false src/main/mdo/archiva-base.xml diff --git a/archiva-modules/archiva-base/archiva-model/src/main/mdo/archiva-base.xml b/archiva-modules/archiva-base/archiva-model/src/main/mdo/archiva-base.xml index de08a8d7b..93e4a295a 100644 --- a/archiva-modules/archiva-base/archiva-model/src/main/mdo/archiva-base.xml +++ b/archiva-modules/archiva-base/archiva-model/src/main/mdo/archiva-base.xml @@ -5,7 +5,7 @@ xsd.target-namespace="http://archiva.apache.org/model/1.2.0"> archiva-base-model ArchivaBaseModel - 1.2.1 + 1.3.0 Archiva Model @@ -75,6 +75,14 @@ * + + archivaAuditLogs + 1.3.0+ + + ArchivaAuditLogs + * + + @@ -2278,5 +2286,70 @@ + + ArchivaAuditLogs + 1.3.0+ + + + repositoryId + 1.3.0+ + false + true + String + + The repository id where the operation was done. + + + + eventDate + 1.3.0+ + false + true + Date + + The timestamp on when the event happened. + + + + artifact + 1.3.0+ + false + false + String + + The affected artifact, if there is one. + + + + event + 1.3.0+ + false + false + String + + The event that happened. + + + + username + 1.3.0+ + false + true + String + + The user who executed the event. + + + + + + 1.3.0+ + + + + diff --git a/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/ArchivaAuditLogsDao.java b/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/ArchivaAuditLogsDao.java new file mode 100644 index 000000000..639c5d623 --- /dev/null +++ b/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/ArchivaAuditLogsDao.java @@ -0,0 +1,35 @@ +package org.apache.maven.archiva.database; + +/* + * 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 org.apache.maven.archiva.model.ArchivaAuditLogs; + +public interface ArchivaAuditLogsDao +{ + public List queryAuditLogs( Constraint constraint ) + throws ObjectNotFoundException, ArchivaDatabaseException; + + public ArchivaAuditLogs saveAuditLogs( ArchivaAuditLogs logs ); + + public void deleteAuditLogs( ArchivaAuditLogs logs ) + throws ArchivaDatabaseException; +} diff --git a/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/ArchivaAuditLogsConstraint.java b/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/ArchivaAuditLogsConstraint.java new file mode 100644 index 000000000..ed225ae6f --- /dev/null +++ b/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/ArchivaAuditLogsConstraint.java @@ -0,0 +1,106 @@ +package org.apache.maven.archiva.database.constraints; + +/* + * 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.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * ArchivaAuditLogsConstraint + */ +public class ArchivaAuditLogsConstraint + extends RangeConstraint +{ + private String whereClause; + + private void createWhereClause( String desiredArtifact, String desiredRepositoryId, String desiredEvent, + Date startDate, Date endDate ) + { + whereClause = "eventDate >= desiredStartDate && eventDate <= desiredEndDate"; + declImports = new String[] { "import java.util.Date" }; + + List declParamsList = new ArrayList(); + declParamsList.add( "Date desiredStartDate" ); + declParamsList.add( "Date desiredEndDate" ); + + List paramsList = new ArrayList(); + paramsList.add( startDate ); + paramsList.add( endDate ); + + if ( desiredArtifact != null && !"".equals( desiredArtifact ) ) + { + whereClause = whereClause + " && artifact.like(desiredArtifact)"; + declParamsList.add( "String desiredArtifact" ); + paramsList.add( desiredArtifact ); + } + + if ( desiredRepositoryId != null && !"".equals( desiredRepositoryId ) ) + { + whereClause = whereClause + " && repositoryId == desiredRepositoryId"; + declParamsList.add( "String desiredRepositoryId" ); + paramsList.add( desiredRepositoryId ); + } + + if ( desiredEvent != null && !"".equals( desiredEvent ) ) + { + whereClause = whereClause + " && event == desiredEvent"; + declParamsList.add( "String desiredEvent" ); + paramsList.add( desiredEvent ); + } + + int size = declParamsList.size(); + int i = 0; + declParams = new String[size]; + + while( i < size ) + { + declParams[i] = declParamsList.get( i ); + i++; + } + + params = paramsList.toArray(); + } + + public ArchivaAuditLogsConstraint( int[] range, String desiredArtifact, String desiredRepositoryId, + String desiredEvent, Date startDate, Date endDate ) + { + super( range ); + createWhereClause( desiredArtifact, desiredRepositoryId, desiredEvent, startDate, endDate ); + } + + public ArchivaAuditLogsConstraint( String desiredArtifact, String desiredRepositoryId, + String desiredEvent, Date startDate, Date endDate ) + { + super(); + createWhereClause( desiredArtifact, desiredRepositoryId, desiredEvent, startDate, endDate ); + } + + + public String getSortColumn() + { + return "eventDate"; + } + + public String getWhereCondition() + { + return whereClause; + } +} diff --git a/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/MostRecentArchivaAuditLogsConstraint.java b/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/MostRecentArchivaAuditLogsConstraint.java new file mode 100644 index 000000000..8e2d00531 --- /dev/null +++ b/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/MostRecentArchivaAuditLogsConstraint.java @@ -0,0 +1,49 @@ +package org.apache.maven.archiva.database.constraints; + +/* + * 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.apache.maven.archiva.model.ArchivaAuditLogs; +import org.apache.maven.archiva.repository.audit.AuditEvent; + +public class MostRecentArchivaAuditLogsConstraint + extends AbstractSimpleConstraint +{ + private String sql; + + public MostRecentArchivaAuditLogsConstraint() + { + sql = + "SELECT FROM " + ArchivaAuditLogs.class.getName() + + " WHERE event == uploadArtifact PARAMETERS String uploadArtifact" + + " ORDER BY eventDate DESCENDING RANGE 0,10"; + + super.params = new Object[] { AuditEvent.UPLOAD_FILE }; + } + + public Class getResultClass() + { + return ArchivaAuditLogs.class; + } + + public String getSelectSql() + { + return sql; + } +} diff --git a/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoAccess.java b/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoAccess.java index 27c39bf52..dd38dfe52 100644 --- a/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoAccess.java +++ b/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoAccess.java @@ -395,7 +395,7 @@ public class JdoAccess case 3: return (List) query.execute( parameters[0], parameters[1], parameters[2] ); default: - throw new JDOException( "Unable to use more than 3 parameters." ); + return (List) query.executeWithArray( parameters ); } } diff --git a/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoArchivaAuditLogsDao.java b/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoArchivaAuditLogsDao.java new file mode 100644 index 000000000..64aa62012 --- /dev/null +++ b/archiva-modules/archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoArchivaAuditLogsDao.java @@ -0,0 +1,62 @@ +package org.apache.maven.archiva.database.jdo; + +/* + * 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 org.apache.maven.archiva.database.ArchivaAuditLogsDao; +import org.apache.maven.archiva.database.ArchivaDatabaseException; +import org.apache.maven.archiva.database.Constraint; +import org.apache.maven.archiva.database.ObjectNotFoundException; +import org.apache.maven.archiva.model.ArchivaAuditLogs; + +/** + * JdoArchivaAuditLogsDao + * + * @version + * + * @plexus.component role-hint="jdo" + */ +public class JdoArchivaAuditLogsDao + implements ArchivaAuditLogsDao +{ + /** + * @plexus.requirement role-hint="archiva" + */ + private JdoAccess jdo; + + public void deleteAuditLogs( ArchivaAuditLogs logs ) + throws ArchivaDatabaseException + { + jdo.removeObject( logs ); + } + + @SuppressWarnings( "unchecked" ) + public List queryAuditLogs( Constraint constraint ) + throws ObjectNotFoundException, ArchivaDatabaseException + { + return (List) jdo.queryObjects( ArchivaAuditLogs.class, constraint ); + } + + public ArchivaAuditLogs saveAuditLogs( ArchivaAuditLogs logs ) + { + return (ArchivaAuditLogs) jdo.saveObject( logs ); + } +} diff --git a/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaRoleConstants.java b/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaRoleConstants.java index 7c6f7b76d..396f9250a 100644 --- a/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaRoleConstants.java +++ b/archiva-modules/archiva-web/archiva-security/src/main/java/org/apache/maven/archiva/security/ArchivaRoleConstants.java @@ -65,6 +65,8 @@ public class ArchivaRoleConstants public static final String OPERATION_REPOSITORY_UPLOAD = "archiva-upload-repository"; public static final String OPERATION_REPOSITORY_DELETE = "archiva-delete-artifact"; + + public static final String OPERATION_VIEW_AUDIT_LOG = "archiva-view-audit-logs"; // Role templates public static final String TEMPLATE_REPOSITORY_MANAGER = "archiva-repository-manager"; diff --git a/archiva-modules/archiva-web/archiva-security/src/main/resources/META-INF/redback/redback.xml b/archiva-modules/archiva-web/archiva-security/src/main/resources/META-INF/redback/redback.xml index 235537e05..55b30e09e 100644 --- a/archiva-modules/archiva-web/archiva-security/src/main/resources/META-INF/redback/redback.xml +++ b/archiva-modules/archiva-web/archiva-security/src/main/resources/META-INF/redback/redback.xml @@ -65,6 +65,11 @@ archiva-access-repository Access Archiva Repository + + archiva-view-audit-logs + archiva-view-audit-logs + View Archiva Audit Logs + archiva-guest archiva-guest @@ -219,6 +224,12 @@ archiva-upload-repository ${resource} + + archiva-view-audit-logs + Archiva View Audit Logs + archiva-view-audit-logs + ${resource} + archiva-repository-observer diff --git a/archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/config/testng.xml b/archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/config/testng.xml index c107bda61..e8607fb3b 100644 --- a/archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/config/testng.xml +++ b/archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/config/testng.xml @@ -33,6 +33,7 @@ under the License. + diff --git a/archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/AuditLogsReportTest.java b/archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/AuditLogsReportTest.java new file mode 100644 index 000000000..bced43169 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp-test/src/test/testng/org/apache/archiva/web/test/AuditLogsReportTest.java @@ -0,0 +1,125 @@ +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.apache.archiva.web.test.parent.AbstractArchivaTest; +import org.testng.annotations.Test; + +@Test( groups = { "auditlogsreport" }, dependsOnMethods = { "testWithCorrectUsernamePassword" } ) +public class AuditLogsReportTest + extends AbstractArchivaTest +{ + private void goToAuditLogReports() + { + clickLinkWithText( "Audit Log Report" ); + } + + private void assertAuditLogsReportPage() + { + assertPage( "Apache Archiva \\ Audit Log Report" ); + assertTextPresent( "Audit Log Report" ); + + assertElementPresent( "repository" ); + assertElementPresent( "groupId" ); + assertElementPresent( "artifactId" ); + assertElementPresent( "startDate" ); + assertElementPresent( "endDate" ); + assertElementPresent( "rowCount" ); + assertButtonWithValuePresent( "View Audit Log" ); + } + + @Test(dependsOnMethods = { "testWithCorrectUsernamePassword" } ) + public void testAuditLogsReport() + { + goToAuditLogReports(); + assertAuditLogsReportPage(); + assertTextPresent( "Latest Events" ); + } + + @Test(dependsOnMethods = { "testWithCorrectUsernamePassword" } ) + public void testViewAuditLogsNoDataFound() + { + goToAuditLogReports(); + assertAuditLogsReportPage(); + + setFieldValue( "groupId", "non.existing" ); + submit(); + + assertPage( "Apache Archiva \\ Audit Log Report" ); + assertTextPresent( "Results" ); + assertTextPresent( "No audit logs found." ); + } + + @Test (dependsOnMethods = { "testAddArtifactValidValues" } ) + public void testViewAuditLogsDataFound() + { + goToAuditLogReports(); + assertAuditLogsReportPage(); + + selectValue( "repository", "internal" ); + setFieldValue( "groupId", "test" ); + submit(); + + assertAuditLogsReportPage(); + assertTextPresent( "Results" ); + assertTextNotPresent( "No audit logs found." ); + assertTextPresent( "test-1.0.jar" ); + assertTextPresent( "Uploaded File" ); + assertTextPresent( "internal" ); + assertTextPresent( "admin" ); + } + + @Test (dependsOnMethods = { "testViewAuditLogsDataFound" } ) + public void testViewAuditLogsOnlyArtifactIdIsSpecified() + { + goToAuditLogReports(); + assertAuditLogsReportPage(); + + selectValue( "repository", "internal" ); + setFieldValue( "artifactId", "test" ); + submit(); + + assertAuditLogsReportPage(); + assertTextPresent( "Results" ); + assertTextNotPresent( "No audit logs found." ); + assertTextPresent( "test-1.0.jar" ); + assertTextPresent( "Uploaded File" ); + assertTextPresent( "internal" ); + assertTextPresent( "admin" ); + } + + @Test (dependsOnMethods = { "testViewAuditLogsOnlyArtifactIdIsSpecified" } ) + public void testViewAuditLogsForAllRepositories() + { + goToAuditLogReports(); + assertAuditLogsReportPage(); + + selectValue( "repository", "all" ); + submit(); + + assertAuditLogsReportPage(); + assertTextPresent( "Results" ); + assertTextNotPresent( "No audit logs found." ); + assertTextPresent( "test-1.0.jar" ); + assertTextPresent( "Uploaded File" ); + assertTextPresent( "internal" ); + assertTextPresent( "admin" ); + } +} diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/PlexusActionSupport.java b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/PlexusActionSupport.java index 5a1d04da7..ad1d38875 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/PlexusActionSupport.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/PlexusActionSupport.java @@ -20,11 +20,14 @@ package org.apache.maven.archiva.web.action; */ import java.util.ArrayList; +import java.util.Calendar; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; +import org.apache.maven.archiva.model.ArchivaAuditLogs; import org.apache.maven.archiva.repository.audit.AuditEvent; import org.apache.maven.archiva.repository.audit.AuditListener; import org.apache.maven.archiva.repository.audit.Auditable; @@ -53,6 +56,11 @@ public abstract class PlexusActionSupport */ private List auditListeners = new ArrayList(); + /** + * @plexus.requirement role-hint="jdo" + */ + private ArchivaAuditLogsDao auditLogsDao; + private String principal; @SuppressWarnings("unchecked") @@ -85,6 +93,15 @@ public abstract class PlexusActionSupport { listener.auditEvent( event ); } + + ArchivaAuditLogs auditLogs = new ArchivaAuditLogs(); + auditLogs.setArtifact( resource ); + auditLogs.setEvent( action ); + auditLogs.setEventDate( Calendar.getInstance().getTime() ); + auditLogs.setRepositoryId( repositoryId ); + auditLogs.setUsername( getPrincipal() ); + + auditLogsDao.saveAuditLogs( auditLogs ); } protected void triggerAuditEvent( String resource, String action ) @@ -129,4 +146,9 @@ public abstract class PlexusActionSupport { this.principal = principal; } + + public void setAuditLogsDao( ArchivaAuditLogsDao auditLogsDao ) + { + this.auditLogsDao = auditLogsDao; + } } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/UploadAction.java b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/UploadAction.java index c61ba16ff..0796850c9 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/UploadAction.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/UploadAction.java @@ -149,7 +149,7 @@ public class UploadAction * @plexus.requirement */ private ArchivaTaskScheduler scheduler; - + private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5}; private ProjectModelWriter pomWriter = new ProjectModel400Writer(); @@ -423,7 +423,7 @@ public class UploadAction String msg = "Artifact \'" + groupId + ":" + artifactId + ":" + version + "\' was successfully deployed to repository \'" + repositoryId + "\'"; - triggerAuditEvent( repositoryId, groupId + ":" + artifactId + ":" + version, AuditEvent.UPLOAD_FILE ); + triggerAuditEvent( repositoryId, artifactPath, AuditEvent.UPLOAD_FILE ); addActionMessage( msg ); diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/reports/ViewAuditLogReportAction.java b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/reports/ViewAuditLogReportAction.java new file mode 100644 index 000000000..298a6d996 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/reports/ViewAuditLogReportAction.java @@ -0,0 +1,433 @@ +package org.apache.maven.archiva.web.action.reports; + +/* + * 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.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.time.DateUtils; +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; +import org.apache.maven.archiva.database.ArchivaDAO; +import org.apache.maven.archiva.database.ArchivaDatabaseException; +import org.apache.maven.archiva.database.ObjectNotFoundException; +import org.apache.maven.archiva.database.SimpleConstraint; +import org.apache.maven.archiva.database.constraints.ArchivaAuditLogsConstraint; +import org.apache.maven.archiva.database.constraints.MostRecentArchivaAuditLogsConstraint; +import org.apache.maven.archiva.model.ArchivaAuditLogs; +import org.apache.maven.archiva.repository.audit.AuditEvent; +import org.apache.maven.archiva.security.AccessDeniedException; +import org.apache.maven.archiva.security.ArchivaSecurityException; +import org.apache.maven.archiva.security.PrincipalNotFoundException; +import org.apache.maven.archiva.security.UserRepositories; +import org.apache.maven.archiva.web.action.PlexusActionSupport; +import org.apache.struts2.interceptor.ServletRequestAware; +import org.codehaus.redback.integration.interceptor.SecureAction; +import org.codehaus.redback.integration.interceptor.SecureActionBundle; +import org.codehaus.redback.integration.interceptor.SecureActionException; + +import com.opensymphony.xwork2.Preparable; + +/** + * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="viewAuditLogReport" + * instantiation-strategy="per-lookup" + */ +public class ViewAuditLogReportAction + extends PlexusActionSupport + implements SecureAction, ServletRequestAware, Preparable +{ + protected HttpServletRequest request; + + /** + * @plexus.requirement + */ + private UserRepositories userRepositories; + + /** + * @plexus.requirement role-hint="jdo" + */ + private ArchivaAuditLogsDao auditLogsDao; + + /** + * @plexus.requirement role-hint="jdo" + */ + private ArchivaDAO dao; + + private String repository; + + private List repositories; + + private String groupId; + + private String artifactId; + + private String startDate; + + private String endDate; + + private int rowCount = 30; + + private int page = 1; + + private String prev; + + private String next; + + protected boolean isLastPage = true; + + private List auditLogs; + + private static final String ALL_REPOSITORIES = "all"; + + protected int[] range = new int[2]; + + private String initial = "true"; + + private String headerName; + + private static final String HEADER_LATEST_EVENTS = "Latest Events"; + + private static final String HEADER_RESULTS = "Results"; + + private String[] datePatterns = new String[] { "MM/dd/yy", "MM/dd/yyyy", "MMMMM/dd/yyyy", "MMMMM/dd/yy", + "dd MMMMM yyyy", "dd/MM/yy", "dd/MM/yyyy", "yyyy/MM/dd", "yyyy-MM-dd", "yyyy-dd-MM", "MM-dd-yyyy", + "MM-dd-yy" }; + + public SecureActionBundle getSecureActionBundle() + throws SecureActionException + { + return null; + } + + public void setServletRequest( HttpServletRequest request ) + { + this.request = request; + } + + @SuppressWarnings( "unchecked" ) + public void prepare() + throws Exception + { + repositories = new ArrayList(); + repositories.add( ALL_REPOSITORIES ); + repositories.addAll( getObservableRepositories() ); + + auditLogs = null; + groupId = ""; + artifactId = ""; + repository = ""; + + if( Boolean.parseBoolean( initial ) ) + { + headerName = HEADER_LATEST_EVENTS; + } + else + { + headerName = HEADER_RESULTS; + } + + SimpleConstraint constraint = new MostRecentArchivaAuditLogsConstraint(); + auditLogs = (List) dao.query( constraint ); + } + + public String execute() + throws Exception + { + auditLogs = null; + String artifact = ""; + + if ( groupId != null && !"".equals( groupId.trim() ) ) + { + artifact = groupId + ( ( artifactId != null && !"".equals( artifactId.trim() ) ) ? ( "/" + artifactId + "/%" ) : "%" ); + } + else + { + artifact = ( artifactId != null && !"".equals( artifactId.trim() ) ) ? ( "%" + artifactId + "%" ) : ""; + } + + Date startDateInDF = null; + Date endDateInDF = null; + if ( startDate == null || "".equals( startDate ) ) + { + Calendar cal = Calendar.getInstance(); + cal.set( Calendar.HOUR, 0 ); + cal.set( Calendar.MINUTE, 0 ); + cal.set( Calendar.SECOND, 0 ); + + startDateInDF = cal.getTime(); + } + else + { + startDateInDF = DateUtils.parseDate( startDate, datePatterns ); + } + + if ( endDate == null || "".equals( endDate ) ) + { + endDateInDF = Calendar.getInstance().getTime(); + } + else + { + endDateInDF = DateUtils.parseDate( endDate, datePatterns ); + Calendar cal = Calendar.getInstance(); + cal.setTime( endDateInDF ); + cal.set( Calendar.HOUR, 23 ); + cal.set( Calendar.MINUTE, 59 ); + cal.set( Calendar.SECOND, 59 ); + + endDateInDF = cal.getTime(); + } + + range[0] = ( page - 1 ) * rowCount; + range[1] = ( page * rowCount ) + 1; + + ArchivaAuditLogsConstraint constraint = null; + if ( !repository.equals( ALL_REPOSITORIES ) ) + { + constraint = + new ArchivaAuditLogsConstraint( range, artifact, repository, AuditEvent.UPLOAD_FILE, startDateInDF, endDateInDF ); + } + else + { + constraint = + new ArchivaAuditLogsConstraint( range, artifact, null, AuditEvent.UPLOAD_FILE, startDateInDF, endDateInDF ); + } + + try + { + auditLogs = auditLogsDao.queryAuditLogs( constraint ); + if( auditLogs.isEmpty() ) + { + addActionError( "No audit logs found." ); + initial = "true"; + } + else + { + initial = "false"; + } + + headerName = HEADER_RESULTS; + paginate(); + } + catch ( ObjectNotFoundException e ) + { + addActionError( "No audit logs found." ); + return ERROR; + } + catch ( ArchivaDatabaseException e ) + { + addActionError( "Error occurred while querying audit logs." ); + return ERROR; + } + + return SUCCESS; + } + + private void paginate() + { + if ( auditLogs.size() <= rowCount ) + { + isLastPage = true; + } + else + { + isLastPage = false; + auditLogs.remove( rowCount ); + } + + prev = + request.getRequestURL() + "?page=" + ( page - 1 ) + "&rowCount=" + rowCount + "&groupId=" + groupId + + "&artifactId=" + artifactId + "&repository=" + repository + "&startDate=" + startDate + "&endDate=" + + endDate; + + next = + request.getRequestURL() + "?page=" + ( page + 1 ) + "&rowCount=" + rowCount + "&groupId=" + groupId + + "&artifactId=" + artifactId + "&repository=" + repository + "&startDate=" + startDate + "&endDate=" + + endDate; + + prev = StringUtils.replace( prev, " ", "%20" ); + next = StringUtils.replace( next, " ", "%20" ); + } + + private List getObservableRepositories() + { + try + { + return userRepositories.getObservableRepositoryIds( getPrincipal() ); + } + catch ( PrincipalNotFoundException e ) + { + log.warn( e.getMessage(), e ); + } + catch ( AccessDeniedException e ) + { + log.warn( e.getMessage(), e ); + } + catch ( ArchivaSecurityException e ) + { + log.warn( e.getMessage(), e ); + } + return Collections.emptyList(); + } + + public String getRepository() + { + return repository; + } + + public void setRepository( String repository ) + { + this.repository = repository; + } + + public List getRepositories() + { + return repositories; + } + + public void setRepositories( List repositories ) + { + this.repositories = repositories; + } + + public String getGroupId() + { + return groupId; + } + + public void setGroupId( String groupId ) + { + this.groupId = groupId; + } + + public String getArtifactId() + { + return artifactId; + } + + public void setArtifactId( String artifactId ) + { + this.artifactId = artifactId; + } + + public List getAuditLogs() + { + return auditLogs; + } + + public void setAuditLogs( List auditLogs ) + { + this.auditLogs = auditLogs; + } + + public int getRowCount() + { + return rowCount; + } + + public void setRowCount( int rowCount ) + { + this.rowCount = rowCount; + } + + public String getStartDate() + { + return startDate; + } + + public void setStartDate( String startDate ) + { + this.startDate = startDate; + } + + public String getEndDate() + { + return endDate; + } + + public void setEndDate( String endDate ) + { + this.endDate = endDate; + } + + public int getPage() + { + return page; + } + + public void setPage( int page ) + { + this.page = page; + } + + public boolean getIsLastPage() + { + return isLastPage; + } + + public void setIsLastPage( boolean isLastPage ) + { + this.isLastPage = isLastPage; + } + + public String getPrev() + { + return prev; + } + + public void setPrev( String prev ) + { + this.prev = prev; + } + + public String getNext() + { + return next; + } + + public void setNext( String next ) + { + this.next = next; + } + + public String getInitial() + { + return initial; + } + + public void setInitial( String initial ) + { + this.initial = initial; + } + + public String getHeaderName() + { + return headerName; + } + + public void setHeaderName( String headerName ) + { + this.headerName = headerName; + } +} diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/resources/struts.xml b/archiva-modules/archiva-web/archiva-webapp/src/main/resources/struts.xml index 8df1acfdd..138843335 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/resources/struts.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/resources/struts.xml @@ -523,6 +523,16 @@ + + + /WEB-INF/jsp/reports/auditLogReport.jsp + + + + /WEB-INF/jsp/reports/auditLogReport.jsp + /WEB-INF/jsp/reports/auditLogReport.jsp + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/default.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/default.jsp index 52ec32bbe..4dc48af6d 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/default.jsp +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/default.jsp @@ -80,7 +80,7 @@ - +
Manage
    @@ -88,6 +88,11 @@ Reports + +
  • + Audit Log Report +
  • +
  • User Management @@ -112,7 +117,7 @@
  • Delete Artifact
  • -
    + <%-- TODO: future options here. * Repository Statistics. * Web Services Statistics. diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/auditLogReport.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/auditLogReport.jsp new file mode 100644 index 000000000..664f8e7fa --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/auditLogReport.jsp @@ -0,0 +1,152 @@ +<%-- + ~ 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. + --%> + +<%@ taglib prefix="s" uri="/struts-tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib uri="http://www.extremecomponents.org" prefix="ec" %> + + + + + Audit Log Report + + + + + + + + + +

    Audit Log Report

    + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Repository:
    Group ID:
    Artifact ID:
    Start Date: + <%-- + + --%> +
    End Date: + <%-- + + --%> +
    Row Count:
    +
    +
    + +

    + +

    + +

    ${headerName}

    +

    + +

    + + + + + + + + + + + + + + + + + + + + +
    EventRepositoryArtifactEvent DateUsername
    ${auditLog.event}${auditLog.repositoryId}${auditLog.artifact}${auditLog.eventDate}${auditLog.username}
    + + + << + Page: ${page} + + >> +
    +
    + +
    + + +
    + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/site.css b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/site.css index a68b439a2..996614608 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/site.css +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/site.css @@ -435,4 +435,46 @@ div.versions { div.versions a.expand { font-size: 7pt; color: gray; -} \ No newline at end of file +} + +table.auditlogs { + text-align: center; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif ; + font-weight: normal; + font-size: 11px; + color: #fff; + width: 100%; + background-color: #666; + border: 0px; + border-collapse: collapse; + border-spacing: 0px; +} + +table.auditlogs th { + background-color: #666; + color: #fff; + padding: 4px; + text-align: center; + border-bottom: 2px #fff solid; + font-size: 12px; + font-weight: bold; +} + +table.auditlogs td { + background-color: #CCC; + color: #000; + padding: 4px; + text-align: center; + border: 1px #fff solid; +} + +div.auditLogReportResults { + border: 1px dashed #DFDEDE; + margin-bottom: 15px; + margin-left: 2px; + padding: 5px; +} + + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/UploadActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/UploadActionTest.java index f86660c56..1af6eda88 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/UploadActionTest.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/UploadActionTest.java @@ -31,6 +31,8 @@ import org.apache.maven.archiva.configuration.ArchivaConfiguration; import org.apache.maven.archiva.configuration.Configuration; import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; import org.apache.maven.archiva.configuration.RepositoryScanningConfiguration; +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; +import org.apache.maven.archiva.model.ArchivaAuditLogs; import org.apache.maven.archiva.repository.ManagedRepositoryContent; import org.apache.maven.archiva.repository.RepositoryContentFactory; import org.apache.maven.archiva.repository.RepositoryNotFoundException; @@ -62,10 +64,14 @@ public class UploadActionTest private RepositoryContentFactory repoFactory; private MockControl repoFactoryControl; + + private ArchivaAuditLogsDao auditLogsDao; + + private MockControl auditLogsDaoControl; private static final String REPOSITORY_ID = "test-repo"; - private Configuration config; + private Configuration config; public void setUp() throws Exception @@ -80,11 +86,16 @@ public class UploadActionTest repoFactoryControl = MockClassControl.createControl( RepositoryContentFactory.class ); repoFactory = (RepositoryContentFactory) repoFactoryControl.getMock(); + + auditLogsDaoControl = MockControl.createControl( ArchivaAuditLogsDao.class ); + auditLogsDaoControl.setDefaultMatcher( MockControl.ALWAYS_MATCHER ); + auditLogsDao = (ArchivaAuditLogsDao) auditLogsDaoControl.getMock(); uploadAction = new UploadAction(); uploadAction.setScheduler( scheduler ); uploadAction.setConfiguration( archivaConfig ); uploadAction.setRepositoryFactory( repoFactory ); + uploadAction.setAuditLogsDao( auditLogsDao ); File testRepo = new File( getBasedir(), "target/test-classes/test-repo" ); testRepo.mkdirs(); @@ -216,16 +227,19 @@ public class UploadActionTest archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config ); repoFactoryControl.expectAndReturn( repoFactory.getManagedRepositoryContent( REPOSITORY_ID ), content ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); archivaConfigControl.replay(); repoFactoryControl.replay(); + auditLogsDaoControl.replay(); String returnString = uploadAction.doUpload(); assertEquals( Action.SUCCESS, returnString ); archivaConfigControl.verify(); repoFactoryControl.verify(); - + auditLogsDaoControl.verify(); + String repoLocation = config.findManagedRepositoryById( REPOSITORY_ID ).getLocation(); assertAllArtifactsIncludingSupportArtifactsArePresent( repoLocation ); @@ -245,15 +259,18 @@ public class UploadActionTest archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config ); repoFactoryControl.expectAndReturn( repoFactory.getManagedRepositoryContent( REPOSITORY_ID ), content ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); archivaConfigControl.replay(); repoFactoryControl.replay(); - + auditLogsDaoControl.replay(); + String returnString = uploadAction.doUpload(); assertEquals( Action.SUCCESS, returnString ); archivaConfigControl.verify(); repoFactoryControl.verify(); + auditLogsDaoControl.verify(); String repoLocation = config.findManagedRepositoryById( REPOSITORY_ID ).getLocation(); assertTrue( new File( repoLocation, "/org/apache/archiva/artifact-upload/1.0/artifact-upload-1.0-tests.jar" ).exists() ); @@ -319,15 +336,18 @@ public class UploadActionTest archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config ); repoFactoryControl.expectAndReturn( repoFactory.getManagedRepositoryContent( REPOSITORY_ID ), content ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); archivaConfigControl.replay(); repoFactoryControl.replay(); + auditLogsDaoControl.replay(); String returnString = uploadAction.doUpload(); assertEquals( Action.SUCCESS, returnString ); archivaConfigControl.verify(); repoFactoryControl.verify(); + auditLogsDaoControl.verify(); String repoLocation = config.findManagedRepositoryById( REPOSITORY_ID ).getLocation(); assertAllArtifactsIncludingSupportArtifactsArePresent( repoLocation ); @@ -377,15 +397,18 @@ public class UploadActionTest archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config ); repoFactoryControl.expectAndReturn( repoFactory.getManagedRepositoryContent( REPOSITORY_ID ), content ); - + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); + archivaConfigControl.replay(); repoFactoryControl.replay(); - + auditLogsDaoControl.replay(); + String returnString = uploadAction.doUpload(); assertEquals( Action.SUCCESS, returnString ); archivaConfigControl.verify(); repoFactoryControl.verify(); + auditLogsDaoControl.verify(); String repoLocation = config.findManagedRepositoryById( REPOSITORY_ID ).getLocation(); assertEquals( 6, new File( repoLocation, "/org/apache/archiva/artifact-upload/1.0-SNAPSHOT/" ).list().length ); @@ -412,18 +435,23 @@ public class UploadActionTest archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config ); repoFactoryControl.expectAndReturn( repoFactory.getManagedRepositoryContent( REPOSITORY_ID ), content ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); archivaConfigControl.replay(); repoFactoryControl.replay(); + auditLogsDaoControl.replay(); String returnString = uploadAction.doUpload(); assertEquals( Action.SUCCESS, returnString ); archivaConfigControl.verify(); repoFactoryControl.verify(); + auditLogsDaoControl.verify(); archivaConfigControl.reset(); repoFactoryControl.reset(); + auditLogsDaoControl.reset(); + auditLogsDaoControl.setDefaultMatcher( MockControl.ALWAYS_MATCHER ); String repoLocation = config.findManagedRepositoryById( REPOSITORY_ID ).getLocation(); assertAllArtifactsIncludingSupportArtifactsArePresent( repoLocation ); @@ -438,15 +466,18 @@ public class UploadActionTest archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config ); repoFactoryControl.expectAndReturn( repoFactory.getManagedRepositoryContent( REPOSITORY_ID ), content ); - + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); + archivaConfigControl.replay(); repoFactoryControl.replay(); + auditLogsDaoControl.replay(); returnString = uploadAction.doUpload(); assertEquals( Action.SUCCESS, returnString ); archivaConfigControl.verify(); repoFactoryControl.verify(); + auditLogsDaoControl.verify(); repoLocation = config.findManagedRepositoryById( REPOSITORY_ID ).getLocation(); assertAllArtifactsIncludingSupportArtifactsArePresent( repoLocation ); @@ -467,9 +498,11 @@ public class UploadActionTest archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config, 2 ); repoFactoryControl.expectAndReturn( repoFactory.getManagedRepositoryContent( REPOSITORY_ID ), content, 2 ); - + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); + archivaConfigControl.replay(); repoFactoryControl.replay(); + auditLogsDaoControl.replay(); String returnString = uploadAction.doUpload(); assertEquals( Action.SUCCESS, returnString ); @@ -484,6 +517,7 @@ public class UploadActionTest archivaConfigControl.verify(); repoFactoryControl.verify(); + auditLogsDaoControl.verify(); String repoLocation = config.findManagedRepositoryById( REPOSITORY_ID ).getLocation(); assertAllArtifactsIncludingSupportArtifactsArePresent( repoLocation ); @@ -506,9 +540,11 @@ public class UploadActionTest archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config, 2 ); repoFactoryControl.expectAndReturn( repoFactory.getManagedRepositoryContent( REPOSITORY_ID ), content, 2 ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null, 2 ); archivaConfigControl.replay(); repoFactoryControl.replay(); + auditLogsDaoControl.replay(); String returnString = uploadAction.doUpload(); assertEquals( Action.SUCCESS, returnString ); @@ -523,6 +559,7 @@ public class UploadActionTest archivaConfigControl.verify(); repoFactoryControl.verify(); + auditLogsDaoControl.verify(); String repoLocation = config.findManagedRepositoryById( REPOSITORY_ID ).getLocation(); assertAllArtifactsIncludingSupportArtifactsArePresent( repoLocation ); diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/DisableProxyConnectorActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/DisableProxyConnectorActionTest.java index b510a144d..becbd156e 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/DisableProxyConnectorActionTest.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/DisableProxyConnectorActionTest.java @@ -40,7 +40,7 @@ public class DisableProxyConnectorActionTest extends AbstractWebworkTestCase private MockControl archivaConfigurationControl; private ArchivaConfiguration archivaConfiguration; - + public void testConfirmDisableBadSourceOrTarget() throws Exception { diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/AddManagedRepositoryActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/AddManagedRepositoryActionTest.java index 5ef78ba39..7accb4b7c 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/AddManagedRepositoryActionTest.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/AddManagedRepositoryActionTest.java @@ -24,6 +24,8 @@ import org.apache.commons.io.FileUtils; import org.apache.maven.archiva.configuration.ArchivaConfiguration; import org.apache.maven.archiva.configuration.Configuration; import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; +import org.apache.maven.archiva.model.ArchivaAuditLogs; import org.apache.maven.archiva.security.ArchivaRoleConstants; import org.codehaus.plexus.redback.role.RoleManager; import org.codehaus.redback.integration.interceptor.SecureActionBundle; @@ -51,6 +53,10 @@ public class AddManagedRepositoryActionTest private MockControl archivaConfigurationControl; private ArchivaConfiguration archivaConfiguration; + + private ArchivaAuditLogsDao auditLogsDao; + + private MockControl auditLogsDaoControl; private static final String REPO_ID = "repo-ident"; @@ -74,6 +80,11 @@ public class AddManagedRepositoryActionTest archivaConfiguration = (ArchivaConfiguration) archivaConfigurationControl.getMock(); action.setArchivaConfiguration( archivaConfiguration ); + auditLogsDaoControl = MockControl.createControl( ArchivaAuditLogsDao.class ); + auditLogsDaoControl.setDefaultMatcher( MockControl.ALWAYS_MATCHER ); + auditLogsDao = (ArchivaAuditLogsDao) auditLogsDaoControl.getMock(); + action.setAuditLogsDao( auditLogsDao ); + roleManagerControl = MockControl.createControl( RoleManager.class ); roleManager = (RoleManager) roleManagerControl.getMock(); action.setRoleManager( roleManager ); @@ -148,15 +159,18 @@ public class AddManagedRepositoryActionTest ManagedRepositoryConfiguration repository = action.getRepository(); populateRepository( repository ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); + auditLogsDaoControl.replay(); + assertFalse( location.exists() ); String status = action.commit(); assertEquals( Action.SUCCESS, status ); - assertTrue( location.exists() ); - + assertTrue( location.exists() ); assertEquals( Collections.singletonList( repository ), configuration.getManagedRepositories() ); roleManagerControl.verify(); archivaConfigurationControl.verify(); + auditLogsDaoControl.verify(); } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/ArchivaAuditLogsDaoStub.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/ArchivaAuditLogsDaoStub.java new file mode 100644 index 000000000..933aeb1c9 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/ArchivaAuditLogsDaoStub.java @@ -0,0 +1,34 @@ +package org.apache.maven.archiva.web.action.admin.repositories; + +import java.util.List; + +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; +import org.apache.maven.archiva.database.ArchivaDatabaseException; +import org.apache.maven.archiva.database.Constraint; +import org.apache.maven.archiva.database.ObjectNotFoundException; +import org.apache.maven.archiva.model.ArchivaAuditLogs; + +public class ArchivaAuditLogsDaoStub + implements ArchivaAuditLogsDao +{ + + public void deleteAuditLogs( ArchivaAuditLogs logs ) + throws ArchivaDatabaseException + { + // TODO Auto-generated method stub + } + + public List queryAuditLogs( Constraint constraint ) + throws ObjectNotFoundException, ArchivaDatabaseException + { + // TODO Auto-generated method stub + return null; + } + + public ArchivaAuditLogs saveAuditLogs( ArchivaAuditLogs logs ) + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/DeleteManagedRepositoryActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/DeleteManagedRepositoryActionTest.java index 8d8c4b2b9..ccd69f49f 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/DeleteManagedRepositoryActionTest.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/DeleteManagedRepositoryActionTest.java @@ -27,6 +27,8 @@ import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration; import org.apache.maven.archiva.configuration.RemoteRepositoryConfiguration; import org.apache.maven.archiva.configuration.RepositoryGroupConfiguration; +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; +import org.apache.maven.archiva.model.ArchivaAuditLogs; import org.apache.maven.archiva.model.ArchivaProjectModel; import org.apache.maven.archiva.security.ArchivaRoleConstants; import org.codehaus.plexus.redback.role.RoleManager; @@ -60,6 +62,10 @@ public class DeleteManagedRepositoryActionTest private ArchivaConfiguration archivaConfiguration; + private ArchivaAuditLogsDao auditLogsDao; + + private MockControl auditLogsDaoControl; + private static final String REPO_ID = "repo-ident"; private File location; @@ -80,6 +86,11 @@ public class DeleteManagedRepositoryActionTest archivaConfigurationControl = MockControl.createControl( ArchivaConfiguration.class ); archivaConfiguration = (ArchivaConfiguration) archivaConfigurationControl.getMock(); action.setArchivaConfiguration( archivaConfiguration ); + + auditLogsDaoControl = MockControl.createControl( ArchivaAuditLogsDao.class ); + auditLogsDaoControl.setDefaultMatcher( MockControl.ALWAYS_MATCHER ); + auditLogsDao = (ArchivaAuditLogsDao) auditLogsDaoControl.getMock(); + action.setAuditLogsDao( auditLogsDao ); roleManagerControl = MockControl.createControl( RoleManager.class ); roleManager = (RoleManager) roleManagerControl.getMock(); @@ -117,9 +128,10 @@ public class DeleteManagedRepositoryActionTest ManagedRepositoryConfiguration repository = action.getRepository(); assertNotNull( repository ); assertRepositoryEquals( repository, createRepository() ); - + String status = action.execute(); assertEquals( Action.SUCCESS, status ); + repository = action.getRepository(); assertRepositoryEquals( repository, createRepository() ); assertEquals( Collections.singletonList( originalRepository ), configuration.getManagedRepositories() ); @@ -132,8 +144,13 @@ public class DeleteManagedRepositoryActionTest Configuration configuration = prepDeletionTest( createRepository(), 4 ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); + auditLogsDaoControl.replay(); + String status = action.deleteEntry(); + auditLogsDaoControl.verify(); + assertEquals( Action.SUCCESS, status ); assertTrue( configuration.getManagedRepositories().isEmpty() ); @@ -148,7 +165,12 @@ public class DeleteManagedRepositoryActionTest Configuration configuration = prepDeletionTest( createRepository(), 4 ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); + auditLogsDaoControl.replay(); + String status = action.deleteContents(); + + auditLogsDaoControl.verify(); assertEquals( Action.SUCCESS, status ); @@ -169,7 +191,12 @@ public class DeleteManagedRepositoryActionTest assertEquals( 1, configuration.getProxyConnectors().size() ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); + auditLogsDaoControl.replay(); + String status = action.deleteContents(); + + auditLogsDaoControl.verify(); assertEquals( Action.SUCCESS, status ); assertTrue( configuration.getManagedRepositories().isEmpty() ); @@ -183,6 +210,7 @@ public class DeleteManagedRepositoryActionTest { ManagedRepositoryConfiguration originalRepository = createRepository(); Configuration configuration = prepDeletionTest( originalRepository, 3 ); + String status = action.execute(); assertEquals( Action.SUCCESS, status ); @@ -205,8 +233,12 @@ public class DeleteManagedRepositoryActionTest assertEquals( 1, configuration.getRepositoryGroups().size() ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); + auditLogsDaoControl.replay(); + String status = action.deleteContents(); assertEquals( Action.SUCCESS, status ); + auditLogsDaoControl.verify(); assertTrue( configuration.getManagedRepositories().isEmpty() ); assertEquals( 0, ( ( RepositoryGroupConfiguration ) configuration.getRepositoryGroups().get( 0 ) ).getRepositories().size() ); diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/EditManagedRepositoryActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/EditManagedRepositoryActionTest.java index e688f8a29..6f9bdf162 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/EditManagedRepositoryActionTest.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/repositories/EditManagedRepositoryActionTest.java @@ -23,9 +23,11 @@ import com.opensymphony.xwork2.Action; import org.apache.maven.archiva.configuration.ArchivaConfiguration; import org.apache.maven.archiva.configuration.Configuration; import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; import org.apache.maven.archiva.database.ArchivaDAO; import org.apache.maven.archiva.database.RepositoryContentStatisticsDAO; import org.apache.maven.archiva.database.constraints.RepositoryContentStatisticsByRepositoryConstraint; +import org.apache.maven.archiva.model.ArchivaAuditLogs; import org.apache.maven.archiva.model.RepositoryContentStatistics; import org.apache.maven.archiva.security.ArchivaRoleConstants; import org.codehaus.plexus.redback.role.RoleManager; @@ -66,6 +68,10 @@ public class EditManagedRepositoryActionTest private MockControl repoContentStatsDaoControl; private RepositoryContentStatisticsDAO repoContentStatsDao; + + private ArchivaAuditLogsDao auditLogsDao; + + private MockControl auditLogsDaoControl; private static final String REPO_ID = "repo-ident"; @@ -96,6 +102,11 @@ public class EditManagedRepositoryActionTest archivaDaoControl = MockControl.createControl( ArchivaDAO.class ); archivaDao = (ArchivaDAO) archivaDaoControl.getMock(); action.setArchivaDAO( archivaDao ); + + auditLogsDaoControl = MockControl.createControl( ArchivaAuditLogsDao.class ); + auditLogsDaoControl.setDefaultMatcher( MockControl.ALWAYS_MATCHER ); + auditLogsDao = (ArchivaAuditLogsDao) auditLogsDaoControl.getMock(); + action.setAuditLogsDao( auditLogsDao ); repoContentStatsDaoControl = MockControl.createControl( RepositoryContentStatisticsDAO.class ); repoContentStatsDao = (RepositoryContentStatisticsDAO) repoContentStatsDaoControl.getMock(); @@ -167,10 +178,13 @@ public class EditManagedRepositoryActionTest ManagedRepositoryConfiguration repository = action.getRepository(); populateRepository( repository ); repository.setName( "new repo name" ); - + + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); + auditLogsDaoControl.replay(); + String status = action.commit(); assertEquals( Action.SUCCESS, status ); - + ManagedRepositoryConfiguration newRepository = createRepository(); newRepository.setName( "new repo name" ); assertRepositoryEquals( repository, newRepository ); @@ -178,6 +192,7 @@ public class EditManagedRepositoryActionTest roleManagerControl.verify(); archivaConfigurationControl.verify(); + auditLogsDaoControl.verify(); } public void testEditRepositoryLocationChanged() @@ -226,6 +241,9 @@ public class EditManagedRepositoryActionTest action.prepare(); assertEquals( REPO_ID, action.getRepoid() ); + auditLogsDaoControl.expectAndReturn( auditLogsDao.saveAuditLogs( new ArchivaAuditLogs() ), null ); + auditLogsDaoControl.replay(); + ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration(); populateRepository( repository ); repository.setLocation( new File( "target/test/location/new" ).getCanonicalPath() ); @@ -238,6 +256,7 @@ public class EditManagedRepositoryActionTest archivaConfigurationControl.verify(); archivaDaoControl.verify(); repoContentStatsDaoControl.verify(); + auditLogsDaoControl.verify(); } private void assertRepositoryEquals( ManagedRepositoryConfiguration expectedRepository, diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/BrowseActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/BrowseActionTest.xml index cccf675cb..bb19ef4c1 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/BrowseActionTest.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/BrowseActionTest.xml @@ -35,5 +35,10 @@ default org.apache.maven.archiva.security.UserRepositoriesStub + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/ShowArtifactActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/ShowArtifactActionTest.xml index d51572b7f..ecd72a3ae 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/ShowArtifactActionTest.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/ShowArtifactActionTest.xml @@ -35,5 +35,10 @@ default org.apache.maven.archiva.security.UserRepositoriesStub + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/appearance/EditOrganizationInfoActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/appearance/EditOrganizationInfoActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/appearance/EditOrganizationInfoActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/appearance/OrganizationInfoActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/appearance/OrganizationInfoActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/appearance/OrganizationInfoActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/AddProxyConnectorActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/AddProxyConnectorActionTest.xml index dc32d3f3d..4ae525c16 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/AddProxyConnectorActionTest.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/AddProxyConnectorActionTest.xml @@ -39,6 +39,10 @@ 1800 - + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/DeleteProxyConnectorActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/DeleteProxyConnectorActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/DeleteProxyConnectorActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/DisableProxyConnectorActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/DisableProxyConnectorActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/DisableProxyConnectorActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/EditProxyConnectorActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/EditProxyConnectorActionTest.xml index dc32d3f3d..a0b969b58 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/EditProxyConnectorActionTest.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/EditProxyConnectorActionTest.xml @@ -38,7 +38,11 @@ 1800 - - + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/EnableProxyConnectorActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/EnableProxyConnectorActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/EnableProxyConnectorActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/ProxyConnectorsActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/ProxyConnectorsActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/ProxyConnectorsActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/SortProxyConnectorsActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/SortProxyConnectorsActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/connectors/proxy/SortProxyConnectorsActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/AbstractManagedRepositoriesActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/AbstractManagedRepositoriesActionTest.xml index afb64ee15..673e760e8 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/AbstractManagedRepositoriesActionTest.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/AbstractManagedRepositoriesActionTest.xml @@ -86,7 +86,11 @@ org.apache.maven.archiva.database.RepositoryContentStatisticsDAO jdo org.apache.maven.archiva.web.action.admin.repositories.RepositoryContentStatisticsDAOStub - - + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/AddRemoteRepositoryActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/AddRemoteRepositoryActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/AddRemoteRepositoryActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteManagedRepositoryActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteManagedRepositoryActionTest.xml index f4d20ee61..0a8e9e743 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteManagedRepositoryActionTest.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteManagedRepositoryActionTest.xml @@ -73,6 +73,11 @@ org.apache.maven.archiva.database.RepositoryContentStatisticsDAO jdo org.apache.maven.archiva.web.action.admin.repositories.RepositoryContentStatisticsDAOStub - + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteRemoteRepositoryActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteRemoteRepositoryActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteRemoteRepositoryActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteRepositoryGroupActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteRepositoryGroupActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/DeleteRepositoryGroupActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/EditRemoteRepositoryActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/EditRemoteRepositoryActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/EditRemoteRepositoryActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/RepositoriesActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/RepositoriesActionTest.xml index c09e524a2..cac84b952 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/RepositoriesActionTest.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/RepositoriesActionTest.xml @@ -48,5 +48,10 @@ + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/RepositoryGroupsActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/RepositoryGroupsActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/RepositoryGroupsActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/SortRepositoriesActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/SortRepositoriesActionTest.xml new file mode 100644 index 000000000..62b568bd8 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/admin/repositories/SortRepositoriesActionTest.xml @@ -0,0 +1,28 @@ + + + + + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + + + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/reports/GenerateReportActionTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/reports/GenerateReportActionTest.xml index dc68e12af..8f21c1462 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/reports/GenerateReportActionTest.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/action/reports/GenerateReportActionTest.xml @@ -45,5 +45,10 @@ org.apache.maven.archiva.web.action.admin.repositories.RepositoryContentStatisticsDAOStub + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + - \ No newline at end of file + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/rss/RssFeedServletTest.xml b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/rss/RssFeedServletTest.xml index 0fec42f00..bb6632ca2 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/rss/RssFeedServletTest.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/rss/RssFeedServletTest.xml @@ -37,5 +37,10 @@ default org.apache.maven.archiva.security.UserRepositoriesStub + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + org.apache.maven.archiva.web.action.admin.repositories.ArchivaAuditLogsDaoStub + diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResource.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResource.java index 113aba0e5..ec4f1b97b 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResource.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResource.java @@ -24,6 +24,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; import javax.servlet.http.HttpServletResponse; @@ -54,6 +55,8 @@ import org.apache.jackrabbit.webdav.property.DavPropertySet; import org.apache.jackrabbit.webdav.property.DefaultDavProperty; import org.apache.jackrabbit.webdav.property.ResourceType; import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; +import org.apache.maven.archiva.model.ArchivaAuditLogs; import org.apache.maven.archiva.repository.audit.AuditEvent; import org.apache.maven.archiva.repository.audit.AuditListener; import org.apache.maven.archiva.scheduled.ArchivaTaskScheduler; @@ -104,11 +107,13 @@ public class ArchivaDavResource private ArchivaTaskScheduler scheduler; private Logger log = LoggerFactory.getLogger( ArchivaDavResource.class ); + + private ArchivaAuditLogsDao auditLogsDao; public ArchivaDavResource( String localResource, String logicalResource, ManagedRepositoryConfiguration repository, DavSession session, ArchivaDavResourceLocator locator, DavResourceFactory factory, MimeTypes mimeTypes, List auditListeners, - ArchivaTaskScheduler scheduler ) + ArchivaTaskScheduler scheduler, ArchivaAuditLogsDao auditLogsDao ) { this.localResource = new File( localResource ); this.logicalResource = logicalResource; @@ -123,15 +128,16 @@ public class ArchivaDavResource this.mimeTypes = mimeTypes; this.auditListeners = auditListeners; this.scheduler = scheduler; + this.auditLogsDao = auditLogsDao; } public ArchivaDavResource( String localResource, String logicalResource, ManagedRepositoryConfiguration repository, String remoteAddr, String principal, DavSession session, ArchivaDavResourceLocator locator, DavResourceFactory factory, MimeTypes mimeTypes, List auditListeners, - ArchivaTaskScheduler scheduler ) + ArchivaTaskScheduler scheduler, ArchivaAuditLogsDao auditLogsDao ) { this( localResource, logicalResource, repository, session, locator, factory, mimeTypes, auditListeners, - scheduler ); + scheduler, auditLogsDao ); this.remoteAddr = remoteAddr; this.principal = principal; @@ -641,6 +647,27 @@ public class ArchivaDavResource { listener.auditEvent( event ); } + + // identify as artifact deployment/upload + if( action.equals( AuditEvent.CREATE_FILE ) ) + { + action = AuditEvent.UPLOAD_FILE; + } + + String user = principal; + if( principal == null ) + { + user = "guest"; + } + + ArchivaAuditLogs auditLogs = new ArchivaAuditLogs(); + auditLogs.setArtifact( resource ); + auditLogs.setEvent( action ); + auditLogs.setEventDate( Calendar.getInstance().getTime() ); + auditLogs.setRepositoryId( repositoryId ); + auditLogs.setUsername( user ); + + auditLogsDao.saveAuditLogs( auditLogs ); } private void queueRepositoryTask( File localFile ) diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java index a297659f5..2684c8ef2 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactory.java @@ -43,6 +43,7 @@ import org.apache.maven.archiva.common.utils.PathUtil; import org.apache.maven.archiva.common.utils.VersionUtil; import org.apache.maven.archiva.configuration.ArchivaConfiguration; import org.apache.maven.archiva.configuration.RepositoryGroupConfiguration; +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; import org.apache.maven.archiva.model.ArchivaRepositoryMetadata; import org.apache.maven.archiva.model.ArtifactReference; import org.apache.maven.archiva.policies.ProxyDownloadException; @@ -168,6 +169,11 @@ public class ArchivaDavResourceFactory * @plexus.requirement */ private ArchivaTaskScheduler scheduler; + + /** + * @plexus.requirement role-hint="jdo" + */ + private ArchivaAuditLogsDao auditLogsDao; public DavResource createResource( final DavResourceLocator locator, final DavServletRequest request, final DavServletResponse response ) @@ -264,7 +270,7 @@ public class ArchivaDavResourceFactory new ArchivaDavResource( metadataChecksum.getAbsolutePath(), logicalResource.getPath(), null, request.getRemoteAddr(), activePrincipal, request.getDavSession(), archivaLocator, this, mimeTypes, - auditListeners, scheduler ); + auditListeners, scheduler, auditLogsDao ); } } else @@ -299,7 +305,7 @@ public class ArchivaDavResourceFactory new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), null, request.getRemoteAddr(), activePrincipal, request.getDavSession(), archivaLocator, this, mimeTypes, - auditListeners, scheduler ); + auditListeners, scheduler, auditLogsDao ); } catch ( RepositoryMetadataException r ) { @@ -418,7 +424,7 @@ public class ArchivaDavResourceFactory resource = new ArchivaDavResource( resourceFile.getAbsolutePath(), path, managedRepository.getRepository(), request.getRemoteAddr(), activePrincipal, request.getDavSession(), - archivaLocator, this, mimeTypes, auditListeners, scheduler ); + archivaLocator, this, mimeTypes, auditListeners, scheduler, auditLogsDao ); if ( WebdavMethodUtil.isReadMethod( request.getMethod() ) ) { @@ -449,7 +455,7 @@ public class ArchivaDavResourceFactory new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource.getPath(), managedRepository.getRepository(), request.getRemoteAddr(), activePrincipal, request.getDavSession(), archivaLocator, this, - mimeTypes, auditListeners, scheduler ); + mimeTypes, auditListeners, scheduler, auditLogsDao ); } catch ( LayoutException e ) { @@ -529,7 +535,7 @@ public class ArchivaDavResourceFactory log.debug( "Creating destination directory '" + destDir.getName() + "' (current user '" + activePrincipal + "')" ); - triggerAuditEvent( request.getRemoteAddr(), logicalResource.getPath(), relPath, + triggerAuditEvent( request.getRemoteAddr(), managedRepository.getId(), relPath, AuditEvent.CREATE_DIR, activePrincipal ); } } @@ -565,7 +571,7 @@ public class ArchivaDavResourceFactory File resourceFile = new File( managedRepository.getRepoRoot(), logicalResource ); DavResource resource = new ArchivaDavResource( resourceFile.getAbsolutePath(), logicalResource, managedRepository.getRepository(), - davSession, archivaLocator, this, mimeTypes, auditListeners, scheduler ); + davSession, archivaLocator, this, mimeTypes, auditListeners, scheduler, auditLogsDao ); resource.addLockManager( lockManager ); return resource; @@ -1093,4 +1099,9 @@ public class ArchivaDavResourceFactory { this.connectors = connectors; } + + public void setAuditLogsDao( ArchivaAuditLogsDao auditLogsDao ) + { + this.auditLogsDao = auditLogsDao; + } } diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactoryTest.java b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactoryTest.java index b2f38fdb4..e5973b08c 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactoryTest.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/ArchivaDavResourceFactoryTest.java @@ -33,6 +33,8 @@ import org.apache.maven.archiva.configuration.ArchivaConfiguration; import org.apache.maven.archiva.configuration.Configuration; import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; import org.apache.maven.archiva.configuration.RepositoryGroupConfiguration; +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; +import org.apache.maven.archiva.model.ArchivaAuditLogs; import org.apache.maven.archiva.proxy.DefaultRepositoryProxyConnectors; import org.apache.maven.archiva.repository.ManagedRepositoryContent; import org.apache.maven.archiva.repository.RepositoryContentFactory; @@ -81,6 +83,10 @@ public class ArchivaDavResourceFactoryTest private MockControl repoContentFactoryControl; private RepositoryContentFactory repoFactory; + + private ArchivaAuditLogsDao auditLogsDao; + + private MockControl auditLogsDaoControl; public void setUp() throws Exception @@ -96,6 +102,10 @@ public class ArchivaDavResourceFactoryTest archivaConfigurationControl = MockControl.createControl( ArchivaConfiguration.class ); archivaConfiguration = (ArchivaConfiguration) archivaConfigurationControl.getMock(); + + auditLogsDaoControl = MockControl.createControl( ArchivaAuditLogsDao.class ); + auditLogsDaoControl.setDefaultMatcher( MockControl.ALWAYS_MATCHER ); + auditLogsDao = (ArchivaAuditLogsDao) auditLogsDaoControl.getMock(); config = new Configuration(); config.addManagedRepository( createManagedRepository( RELEASES_REPO, new File( getBasedir(), @@ -125,6 +135,7 @@ public class ArchivaDavResourceFactoryTest resourceFactory.setRepositoryFactory( repoFactory ); resourceFactory.setRepositoryRequest( repoRequest ); resourceFactory.setConnectors( new OverridingRepositoryProxyConnectors() ); + resourceFactory.setAuditLogsDao( auditLogsDao ); } private ManagedRepositoryConfiguration createManagedRepository( String id, String location, String layout ) @@ -392,7 +403,7 @@ public class ArchivaDavResourceFactoryTest long date = 2039842134; response.addDateHeader( "last-modified", date ); responseControl.setVoidCallable(); - + archivaConfigurationControl.replay(); repoContentFactoryControl.replay(); requestControl.replay(); diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/DavResourceTest.java b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/DavResourceTest.java index 937907585..a3c2d6eb9 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/DavResourceTest.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/DavResourceTest.java @@ -20,7 +20,9 @@ package org.apache.maven.archiva.webdav; */ import java.io.File; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import org.apache.commons.io.FileUtils; import org.apache.jackrabbit.webdav.DavException; @@ -37,12 +39,15 @@ import org.apache.jackrabbit.webdav.lock.Scope; import org.apache.jackrabbit.webdav.lock.SimpleLockManager; import org.apache.jackrabbit.webdav.lock.Type; import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration; +import org.apache.maven.archiva.database.ArchivaAuditLogsDao; +import org.apache.maven.archiva.database.ArchivaDatabaseException; +import org.apache.maven.archiva.database.Constraint; +import org.apache.maven.archiva.database.ObjectNotFoundException; +import org.apache.maven.archiva.model.ArchivaAuditLogs; import org.apache.maven.archiva.repository.audit.AuditListener; -import org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers; import org.apache.maven.archiva.webdav.util.MimeTypes; import org.codehaus.plexus.spring.PlexusInSpringTestCase; import org.codehaus.plexus.spring.PlexusToSpringUtils; -import org.codehaus.plexus.taskqueue.execution.TaskQueueExecutor; public class DavResourceTest extends PlexusInSpringTestCase @@ -67,23 +72,27 @@ public class DavResourceTest private ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration(); + private ArchivaAuditLogsDao auditLogsDao; + @Override protected void setUp() throws Exception { super.setUp(); session = new ArchivaDavSession(); + auditLogsDao = new ArchivaAuditLogsDaoImpl(); mimeTypes = (MimeTypes) getApplicationContext().getBean( PlexusToSpringUtils.buildSpringId( MimeTypes.class ) ); baseDir = getTestFile( "target/DavResourceTest" ); baseDir.mkdirs(); myResource = new File( baseDir, "myresource.jar" ); assertTrue( "Could not create " + myResource.getAbsolutePath(), myResource.createNewFile() ); resourceFactory = new RootContextDavResourceFactory(); + resourceLocator = - (ArchivaDavResourceLocator) new ArchivaDavLocatorFactory().createResourceLocator( "/", REPOPATH ); + (ArchivaDavResourceLocator) new ArchivaDavLocatorFactory().createResourceLocator( "/", REPOPATH ); resource = getDavResource( resourceLocator.getHref( false ), myResource ); lockManager = new SimpleLockManager(); - resource.addLockManager( lockManager ); + resource.addLockManager( lockManager ); } @Override @@ -98,7 +107,7 @@ public class DavResourceTest private DavResource getDavResource( String logicalPath, File file ) { return new ArchivaDavResource( file.getAbsolutePath(), logicalPath, repository, session, resourceLocator, - resourceFactory, mimeTypes, Collections. emptyList(), null ); + resourceFactory, mimeTypes, Collections. emptyList(), null, auditLogsDao ); } public void testDeleteNonExistantResourceShould404() @@ -305,7 +314,28 @@ public class DavResourceTest { return new ArchivaDavResource( baseDir.getAbsolutePath(), "/", repository, session, resourceLocator, resourceFactory, mimeTypes, Collections. emptyList(), - null ); + null, auditLogsDao ); + } + } + + private class ArchivaAuditLogsDaoImpl + implements ArchivaAuditLogsDao + { + public List queryAuditLogs( Constraint constraint ) + throws ObjectNotFoundException, ArchivaDatabaseException + { + return new ArrayList(); + } + + public ArchivaAuditLogs saveAuditLogs( ArchivaAuditLogs logs ) + { + return new ArchivaAuditLogs(); + } + + public void deleteAuditLogs( ArchivaAuditLogs logs ) + throws ArchivaDatabaseException + { + } } } diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.java b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.java index 9066331de..f4119959f 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.java +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/java/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.java @@ -39,6 +39,7 @@ import org.codehaus.plexus.redback.authentication.AuthenticationResult; import org.codehaus.plexus.redback.authorization.UnauthorizedException; import org.codehaus.plexus.redback.system.DefaultSecuritySession; import org.codehaus.plexus.redback.system.SecuritySession; +import org.codehaus.plexus.redback.users.User; import org.codehaus.plexus.redback.users.memory.SimpleUser; import org.codehaus.plexus.spring.PlexusInSpringTestCase; import org.codehaus.redback.integration.filter.authentication.HttpAuthenticator; @@ -352,11 +353,14 @@ public class RepositoryServletSecurityTest httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, null ), true ); + User user = new SimpleUser(); + user.setUsername( "admin" ); + // ArchivaDavResourceFactory#isAuthorized() SecuritySession session = new DefaultSecuritySession(); httpAuthControl.expectAndReturn( httpAuth.getAuthenticationResult( null, null ), result ); httpAuthControl.expectAndReturn( httpAuth.getSecuritySession( ic.getRequest().getSession( true ) ), session ); - httpAuthControl.expectAndReturn( httpAuth.getSessionUser( ic.getRequest().getSession() ), new SimpleUser() ); + httpAuthControl.expectAndReturn( httpAuth.getSessionUser( ic.getRequest().getSession() ), user ); servletAuthControl.expectAndReturn( servletAuth.isAuthenticated( null, result ), true ); servletAuthControl.expectAndReturn( servletAuth.isAuthorized( null, session, "internal", diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.xml b/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.xml index bd9196bdf..719bc5f01 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.xml +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletSecurityTest.xml @@ -148,6 +148,11 @@ org.apache.maven.archiva.scheduled.ArchivaTaskScheduler scheduler + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + auditLogsDao + diff --git a/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletTest.xml b/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletTest.xml index 74a63e922..4ee64c61b 100644 --- a/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletTest.xml +++ b/archiva-modules/archiva-web/archiva-webdav/src/test/resources/org/apache/maven/archiva/webdav/RepositoryServletTest.xml @@ -160,6 +160,11 @@ org.apache.maven.archiva.scheduled.ArchivaTaskScheduler scheduler + + org.apache.maven.archiva.database.ArchivaAuditLogsDao + jdo + auditLogsDao + -- 2.39.5