From: Martin Stockhammer Date: Thu, 16 Dec 2021 23:10:02 +0000 (+0100) Subject: [MRM-2026] Improving audit log X-Git-Tag: archiva-2.2.7~9 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8ed54feb5885857c714ecc80d466b56eaeb25818;p=archiva.git [MRM-2026] Improving audit log --- diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.fdt b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.fdt new file mode 100644 index 000000000..bdbf9e89e Binary files /dev/null and b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.fdt differ diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.fdx b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.fdx new file mode 100644 index 000000000..b8ee80957 Binary files /dev/null and b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.fdx differ diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.fnm b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.fnm new file mode 100644 index 000000000..54c9c6652 --- /dev/null +++ b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.fnm @@ -0,0 +1,2 @@ +ýÿÿÿ +DESCRIPTORIDXINFO \ No newline at end of file diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.frq b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.frq new file mode 100644 index 000000000..6b2aaa764 --- /dev/null +++ b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.frq @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.nrm b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.nrm new file mode 100644 index 000000000..98f7c5aa6 --- /dev/null +++ b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.nrm @@ -0,0 +1 @@ +NRMÿ| \ No newline at end of file diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.prx b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.prx new file mode 100644 index 000000000..f76dd238a Binary files /dev/null and b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.prx differ diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.tii b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.tii new file mode 100644 index 000000000..509d02d09 Binary files /dev/null and b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.tii differ diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.tis b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.tis new file mode 100644 index 000000000..67da5290e Binary files /dev/null and b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/_0.tis differ diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/segments.gen b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/segments.gen new file mode 100644 index 000000000..225a55b3c Binary files /dev/null and b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/segments.gen differ diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/segments_2 b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/segments_2 new file mode 100644 index 000000000..e1bc4ee76 Binary files /dev/null and b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/segments_2 differ diff --git a/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/write.lock b/archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/repositories/default-repository/.indexer/write.lock new file mode 100644 index 000000000..e69de29bb diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/interceptors/AuditInfoFilter.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/interceptors/AuditInfoFilter.java new file mode 100644 index 000000000..a0cdb4b7c --- /dev/null +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/interceptors/AuditInfoFilter.java @@ -0,0 +1,161 @@ +package org.apache.archiva.rest.services.interceptors; + +/* + * 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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.core.Context; +import javax.ws.rs.ext.Provider; +import java.io.IOException; + +/** + * @since + */ +@Service("auditInfoFilter#rest") +@Provider +public class AuditInfoFilter implements ContainerRequestFilter +{ + + private static final Logger log = LoggerFactory.getLogger( AuditInfoFilter.class ); + + @Context + private HttpServletRequest servletRequest; + + private static final AuditInfoThreadLocal auditInfoThreadLocal = new AuditInfoThreadLocal(); + + public AuditInfoFilter() { + + } + + public static class AuditInfoThreadLocal extends ThreadLocal { + + public AuditInfoThreadLocal() { + + } + + @Override + protected AuditInfo initialValue( ) + { + return new AuditInfo(); + } + } + + public static class AuditInfo { + + private String remoteAddress = "0.0.0.0"; + private String localAddress = "0.0.0.0"; + private String remoteHost = "0.0.0.0"; + private String protocol = ""; + private int remotePort = 0; + private String method = ""; + + public AuditInfo() { + + } + + public String getRemoteAddress( ) + { + return remoteAddress; + } + + public void setRemoteAddress( String remoteAddress ) + { + this.remoteAddress = remoteAddress; + } + + public String getLocalAddress( ) + { + return localAddress; + } + + public void setLocalAddress( String localAddress ) + { + this.localAddress = localAddress; + } + + public String getRemoteHost( ) + { + return remoteHost; + } + + public void setRemoteHost( String remoteHost ) + { + this.remoteHost = remoteHost; + } + + public int getRemotePort( ) + { + return remotePort; + } + + public void setRemotePort( int remotePort ) + { + this.remotePort = remotePort; + } + + public String getMethod( ) + { + return method; + } + + public void setMethod( String method ) + { + this.method = method; + } + + public String getProtocol( ) + { + return protocol; + } + + public void setProtocol( String protocol ) + { + this.protocol = protocol; + } + } + + + + @Override + public void filter( ContainerRequestContext containerRequestContext ) throws IOException + { + if (log.isDebugEnabled()) + { + log.debug( "Filter {}, {}", servletRequest.getRemoteAddr( ), servletRequest.getRemoteHost( ) ); + } + AuditInfo auditInfo = auditInfoThreadLocal.get( ); + auditInfo.setRemoteAddress( servletRequest.getRemoteAddr( ) ); + auditInfo.setLocalAddress( servletRequest.getLocalAddr( ) ); + auditInfo.setProtocol( servletRequest.getProtocol( ) ); + auditInfo.setRemoteHost( servletRequest.getRemoteHost( ) ); + auditInfo.setRemotePort( servletRequest.getRemotePort( ) ); + auditInfo.setMethod( containerRequestContext.getMethod( ) ); + } + + public static AuditInfo getAuditInfo() { + return auditInfoThreadLocal.get( ); + } +} diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/resources/META-INF/spring-context.xml b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/resources/META-INF/spring-context.xml index c9e677db6..f51795d86 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/resources/META-INF/spring-context.xml +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/resources/META-INF/spring-context.xml @@ -50,6 +50,7 @@ + diff --git a/archiva-modules/archiva-web/archiva-web-common/src/main/java/org/apache/archiva/web/security/ArchivaUserManagerAuthenticator.java b/archiva-modules/archiva-web/archiva-web-common/src/main/java/org/apache/archiva/web/security/ArchivaUserManagerAuthenticator.java index 0a74e395b..95b6d4db6 100644 --- a/archiva-modules/archiva-web/archiva-web-common/src/main/java/org/apache/archiva/web/security/ArchivaUserManagerAuthenticator.java +++ b/archiva-modules/archiva-web/archiva-web-common/src/main/java/org/apache/archiva/web/security/ArchivaUserManagerAuthenticator.java @@ -20,6 +20,7 @@ package org.apache.archiva.web.security; import org.apache.archiva.admin.model.RepositoryAdminException; import org.apache.archiva.admin.model.runtime.RedbackRuntimeConfigurationAdmin; +import org.apache.archiva.metadata.model.facets.AuditEvent; import org.apache.archiva.redback.authentication.AbstractAuthenticator; import org.apache.archiva.redback.authentication.AuthenticationConstants; import org.apache.archiva.redback.authentication.AuthenticationDataSource; @@ -35,6 +36,8 @@ import org.apache.archiva.redback.policy.UserSecurityPolicy; import org.apache.archiva.redback.users.User; import org.apache.archiva.redback.users.UserManager; import org.apache.archiva.redback.users.UserNotFoundException; +import org.apache.archiva.repository.events.AuditListener; +import org.apache.archiva.rest.services.interceptors.AuditInfoFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; @@ -65,6 +68,9 @@ public class ArchivaUserManagerAuthenticator @Inject private RedbackRuntimeConfigurationAdmin redbackRuntimeConfigurationAdmin; + @Inject + private List auditListeners = new ArrayList<>(); + private List userManagers; private boolean valid = false; @@ -94,6 +100,27 @@ public class ArchivaUserManagerAuthenticator } } + protected AuditInfoFilter.AuditInfo getAuditInformation() + { + return AuditInfoFilter.getAuditInfo( ); + } + + public List getAuditListeners() + { + return auditListeners; + } + + protected void triggerAuditEvent( String repositoryId, String filePath, String action, String user ) + { + AuditEvent auditEvent = new AuditEvent( repositoryId, user, filePath, action ); + AuditInfoFilter.AuditInfo auditInformation = getAuditInformation(); + auditEvent.setUserId( user ); + auditEvent.setRemoteIP( auditInformation.getRemoteHost() + ":" + auditInformation.getRemotePort() ); + for ( AuditListener auditListener : getAuditListeners() ) + { + auditListener.auditEvent( auditEvent ); + } + } @Override public AuthenticationResult authenticate( AuthenticationDataSource ds ) @@ -104,21 +131,23 @@ public class ArchivaUserManagerAuthenticator Exception resultException = null; PasswordBasedAuthenticationDataSource source = (PasswordBasedAuthenticationDataSource) ds; List authnResultErrors = new ArrayList<>(); + final String loginUserId = source.getUsername( ); for ( UserManager userManager : userManagers ) { try { log.debug( "Authenticate: {} with userManager: {}", source, userManager.getId() ); - User user = userManager.findUser( source.getUsername() ); + User user = userManager.findUser( loginUserId ); username = user.getUsername(); if ( user.isLocked() ) { //throw new AccountLockedException( "Account " + source.getUsername() + " is locked.", user ); AccountLockedException e = - new AccountLockedException( "Account " + source.getUsername() + " is locked.", user ); + new AccountLockedException( "Account " + loginUserId + " is locked.", user ); log.warn( "{}", e.getMessage() ); + triggerAuditEvent( "", "", "login-account-locked", loginUserId ); resultException = e; authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_LOCKED_USER_EXCEPTION, @@ -131,6 +160,7 @@ public class ArchivaUserManagerAuthenticator MustChangePasswordException e = new MustChangePasswordException( "Password expired.", user ); log.warn( "{}", e.getMessage() ); resultException = e; + triggerAuditEvent( "", "", "login-password-change-required", loginUserId ); authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_MUST_CHANGE_PASSWORD_EXCEPTION, e.getMessage() ) ); @@ -142,13 +172,15 @@ public class ArchivaUserManagerAuthenticator boolean isPasswordValid = encoder.isPasswordValid( user.getEncodedPassword(), source.getPassword() ); if ( isPasswordValid ) { - log.debug( "User {} provided a valid password", source.getUsername() ); + log.debug( "User {} provided a valid password", loginUserId ); try { securityPolicy.extensionPasswordExpiration( user ); authenticationSuccess = true; + triggerAuditEvent( "", "", "login-success", loginUserId ); + //REDBACK-151 do not make unnessesary updates to the user object if ( user.getCountFailedLoginAttempts() > 0 ) @@ -160,11 +192,12 @@ public class ArchivaUserManagerAuthenticator } } - return new AuthenticationResult( true, source.getUsername(), null ); + return new AuthenticationResult( true, loginUserId, null ); } catch ( MustChangePasswordException e ) { user.setPasswordChangeRequired( true ); + triggerAuditEvent( "", "", "login-password-change-required", loginUserId ); //throw e; resultException = e; authnResultErrors.add( new AuthenticationFailureCause( @@ -175,6 +208,8 @@ public class ArchivaUserManagerAuthenticator { log.warn( "Password is Invalid for user {} and userManager '{}'.", source.getUsername(), userManager.getId() ); + triggerAuditEvent( "", "", "login-authentication-failed", loginUserId ); + authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER, "Password is Invalid for user " + source.getUsername() + "." ).user( user ) ); @@ -198,18 +233,20 @@ public class ArchivaUserManagerAuthenticator } catch ( UserNotFoundException e ) { - log.warn( "Login for user {} and userManager {} failed. user not found.", source.getUsername(), + log.warn( "Login for user {} and userManager {} failed. user not found.", loginUserId, userManager.getId() ); resultException = e; + triggerAuditEvent( "", "", "login-user-unknown", loginUserId ); authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_NO_SUCH_USER, "Login for user " + source.getUsername() + " failed. user not found." ) ); } catch ( Exception e ) { - log.warn( "Login for user {} and userManager {} failed, message: {}", source.getUsername(), + log.warn( "Login for user {} and userManager {} failed, message: {}", loginUserId, userManager.getId(), e.getMessage() ); resultException = e; + triggerAuditEvent( "", "", "login-error", loginUserId ); authnResultErrors.add( new AuthenticationFailureCause( AuthenticationConstants.AUTHN_RUNTIME_EXCEPTION, "Login for user " + source.getUsername() + " failed, message: " + e.getMessage() ) ); diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/resources/log4j2.xml b/archiva-modules/archiva-web/archiva-webapp/src/main/resources/log4j2.xml index f22ee0691..462ebddfb 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/resources/log4j2.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/resources/log4j2.xml @@ -40,7 +40,7 @@ + immediateFlush="true" append="true"> %d{yyyy-MM-dd HH:mm:ss} %m%n @@ -49,24 +49,9 @@ - - - %d{yyyy-MM-dd HH:mm:ss} - %X{redback.currentUser} - %m%n - - - - - - - - - - diff --git a/archiva-modules/plugins/audit/src/main/java/org/apache/archiva/audit/AuditLog.java b/archiva-modules/plugins/audit/src/main/java/org/apache/archiva/audit/AuditLog.java index 37b5a5211..bd6887d02 100644 --- a/archiva-modules/plugins/audit/src/main/java/org/apache/archiva/audit/AuditLog.java +++ b/archiva-modules/plugins/audit/src/main/java/org/apache/archiva/audit/AuditLog.java @@ -54,7 +54,6 @@ public class AuditLog msg.append( checkNull( event.getRemoteIP() ) ).append( DELIM ); msg.append( '\"' ).append( checkNull( event.getResource() ) ).append( '\"' ).append( DELIM ); msg.append( '\"' ).append( event.getAction() ).append( '\"' ); - logger.info( msg.toString() ); }