From 510d21aa0975599105ccbe2bceea1ff94db0d325 Mon Sep 17 00:00:00 2001 From: Martin Stockhammer Date: Mon, 4 Jan 2021 15:22:36 +0100 Subject: [PATCH] Adding REST v2 implementations --- .../v2/SecurityConfigurationService.java | 136 +++++++++- .../DefaultSecurityConfigurationService.java | 248 ++++++++++++++++++ .../archiva/rest/services/v2/ErrorKeys.java | 6 +- 3 files changed, 384 insertions(+), 6 deletions(-) diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/SecurityConfigurationService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/SecurityConfigurationService.java index 5292c0e91..1a22c0d1b 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/SecurityConfigurationService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/SecurityConfigurationService.java @@ -18,8 +18,11 @@ package org.apache.archiva.rest.api.services.v2;/* import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; @@ -32,12 +35,16 @@ import org.apache.archiva.rest.api.model.v2.LdapConfiguration; import org.apache.archiva.rest.api.model.v2.SecurityConfiguration; import org.apache.archiva.security.common.ArchivaRoleConstants; +import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; +import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import java.util.List; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; @@ -58,7 +65,7 @@ public interface SecurityConfigurationService { @Path("config") @GET - @Produces({ MediaType.APPLICATION_JSON }) + @Produces({ APPLICATION_JSON }) @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) @Operation( summary = "Returns the security configuration that is currently active.", security = { @@ -77,6 +84,28 @@ public interface SecurityConfigurationService SecurityConfiguration getConfiguration() throws ArchivaRestServiceException; + @Path("config") + @PUT + @Consumes({ APPLICATION_JSON }) + @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) + @Operation( summary = "Updates the security configuration.", + security = { + @SecurityRequirement( + name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION + ) + }, + responses = { + @ApiResponse( responseCode = "200", + description = "If the configuration was updated" + ), + @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to update the configuration", + content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) ) + } + ) + Response updateConfiguration( SecurityConfiguration newConfiguration) + throws ArchivaRestServiceException; + + @Path( "config/properties" ) @GET @Produces( { APPLICATION_JSON } ) @@ -109,9 +138,64 @@ public interface SecurityConfigurationService @QueryParam( "orderBy") @DefaultValue( "key" ) List orderBy, @QueryParam("order") @DefaultValue( "asc" ) String order ) throws ArchivaRestServiceException; + @Path("config/properties/{propertyName}") + @GET + @Produces({ APPLICATION_JSON }) + @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) + @Operation( summary = "Returns a single configuration property value.", + security = { + @SecurityRequirement( + name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION + ) + }, + parameters = { + @Parameter(in = ParameterIn.PATH, name="propertyName", description = "The name of the property to update") + }, + responses = { + @ApiResponse( responseCode = "200", + description = "If the configuration could be retrieved" + ), + @ApiResponse( responseCode = "404", description = "The given property name does not exist", + content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) ), + @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information", + content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) ) + } + ) + PropertyEntry getConfigurationProperty( @PathParam ( "propertyName" ) String propertyName) + throws ArchivaRestServiceException; + + + @Path("config/properties/{propertyName}") + @PUT + @Consumes({ APPLICATION_JSON}) + @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) + @Operation( summary = "Updates a single property value of the security configuration.", + security = { + @SecurityRequirement( + name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION + ) + }, + requestBody = @RequestBody(required = true, description = "The property value"), + parameters = { + @Parameter(in = ParameterIn.PATH, name="propertyName", description = "The name of the property to update") + }, + responses = { + @ApiResponse( responseCode = "200", + description = "If the property value was updated." + ), + @ApiResponse( responseCode = "404", description = "The given property name does not exist", + content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) ), + @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information", + content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) ) + } + ) + Response updateConfigurationProperty( @PathParam ( "propertyName" ) String propertyName, PropertyEntry propertyValue) + throws ArchivaRestServiceException; + + @Path("config/ldap") @GET - @Produces({ MediaType.APPLICATION_JSON }) + @Produces({ APPLICATION_JSON }) @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) @Operation( summary = "Returns the LDAP configuration that is currently active.", security = { @@ -129,10 +213,30 @@ public interface SecurityConfigurationService ) LdapConfiguration getLdapConfiguration( ) throws ArchivaRestServiceException; + @Path("config/ldap") + @PUT + @Consumes({ APPLICATION_JSON }) + @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) + @Operation( summary = "Updates the LDAP configuration that is currently active.", + security = { + @SecurityRequirement( + name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION + ) + }, + requestBody = @RequestBody(required = true, description = "The LDAP configuration"), + responses = { + @ApiResponse( responseCode = "200", + description = "If the configuration was updated" + ), + @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to update the information", + content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) ) + } + ) + Response updateLdapConfiguration( LdapConfiguration configuration ) throws ArchivaRestServiceException; @Path("config/cache") @GET - @Produces({ MediaType.APPLICATION_JSON }) + @Produces({ APPLICATION_JSON }) @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) @Operation( summary = "Returns the cache configuration that is currently active.", security = { @@ -150,9 +254,31 @@ public interface SecurityConfigurationService ) CacheConfiguration getCacheConfiguration( ) throws ArchivaRestServiceException; + @Path("config/cache") + @PUT + @Consumes({ APPLICATION_JSON }) + @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) + @Operation( summary = "Updates the LDAP configuration that is currently active.", + security = { + @SecurityRequirement( + name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION + ) + }, + requestBody = @RequestBody(required = true, description = "The LDAP configuration"), + responses = { + @ApiResponse( responseCode = "200", + description = "If the configuration was updated" + ), + @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to update the information", + content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) ) + } + ) + Response updateCacheConfiguration( CacheConfiguration cacheConfiguration ) throws ArchivaRestServiceException; + + @Path("user_managers") @GET - @Produces({ MediaType.APPLICATION_JSON }) + @Produces({ APPLICATION_JSON }) @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) @Operation( summary = "Returns the available user manager implementations.", security = { @@ -173,7 +299,7 @@ public interface SecurityConfigurationService @Path("rbac_managers") @GET - @Produces({ MediaType.APPLICATION_JSON }) + @Produces({ APPLICATION_JSON }) @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) @Operation( summary = "Returns the available RBAC manager implementations.", security = { diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java index b9b504c85..be76f3164 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java @@ -19,11 +19,18 @@ package org.apache.archiva.rest.services.v2;/* import org.apache.archiva.admin.model.RepositoryAdminException; import org.apache.archiva.admin.model.beans.RedbackRuntimeConfiguration; import org.apache.archiva.admin.model.runtime.RedbackRuntimeConfigurationAdmin; +import org.apache.archiva.components.cache.Cache; import org.apache.archiva.components.rest.model.PagedResult; import org.apache.archiva.components.rest.model.PropertyEntry; import org.apache.archiva.components.rest.util.PagingHelper; import org.apache.archiva.components.rest.util.QueryHelper; +import org.apache.archiva.redback.authentication.Authenticator; +import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory; +import org.apache.archiva.redback.common.ldap.user.LdapUserMapper; +import org.apache.archiva.redback.policy.CookieSettings; +import org.apache.archiva.redback.policy.PasswordRule; import org.apache.archiva.redback.rbac.RBACManager; +import org.apache.archiva.redback.role.RoleManager; import org.apache.archiva.redback.users.UserManager; import org.apache.archiva.rest.api.model.UserManagerImplementationInformation; import org.apache.archiva.rest.api.model.v2.BeanInformation; @@ -33,6 +40,8 @@ import org.apache.archiva.rest.api.model.v2.SecurityConfiguration; import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException; import org.apache.archiva.rest.api.services.v2.ErrorMessage; import org.apache.archiva.rest.api.services.v2.SecurityConfigurationService; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,8 +50,11 @@ import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.inject.Inject; +import javax.inject.Named; import javax.management.Query; +import javax.ws.rs.core.Response; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -81,6 +93,29 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio @Inject private ApplicationContext applicationContext; + @Inject + @Named(value = "userManager#default") + private UserManager userManager; + + @Inject + @Named(value = "rbacManager#default") + private RBACManager rbacManager; + + @Inject + private RoleManager roleManager; + + @Inject + @Named(value = "ldapConnectionFactory#configurable") + private LdapConnectionFactory ldapConnectionFactory; + + @Inject + private LdapUserMapper ldapUserMapper; + + @Inject + @Named(value = "cache#users") + private Cache usersCache; + + @PostConstruct void init() { bundle = ResourceBundle.getBundle( "org.apache.archiva.rest.RestBundle" ); @@ -103,6 +138,135 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) ); } } + private void updateConfig(SecurityConfiguration newConfig, RedbackRuntimeConfiguration rbConfig) { + rbConfig.setUserManagerImpls( newConfig.getActiveUserManagers() ); + rbConfig.setRbacManagerImpls( newConfig.getActiveRbacManagers() ); + rbConfig.setUseUsersCache( newConfig.isUserCacheEnabled() ); + Map props = rbConfig.getConfigurationProperties( ); + for ( Map.Entry newProp : newConfig.getProperties().entrySet() ) { + props.put( newProp.getKey( ), newProp.getValue( ) ); + } + } + + private void updateConfig(LdapConfiguration newConfig, RedbackRuntimeConfiguration rbConfig) { + org.apache.archiva.admin.model.beans.LdapConfiguration ldapConfig = rbConfig.getLdapConfiguration( ); + ldapConfig.setBaseDn( newConfig.getBaseDn( ) ); + ldapConfig.setAuthenticationMethod( newConfig.getAuthenticationMethod() ); + ldapConfig.setBindAuthenticatorEnabled( newConfig.isBindAuthenticatorEnabled( ) ); + ldapConfig.setBindDn( newConfig.getBindDn() ); + ldapConfig.setSsl( newConfig.isSslEnabled( ) ); + ldapConfig.setBaseGroupsDn( newConfig.getGroupsBaseDn() ); + ldapConfig.setHostName( newConfig.getHostName() ); + ldapConfig.setPort( newConfig.getPort() ); + ldapConfig.setPassword( newConfig.getBindPassword() ); + ldapConfig.setUseRoleNameAsGroup( newConfig.isUseRoleNameAsGroup() ); + ldapConfig.setWritable( newConfig.isWritable( ) ); + + Map props = ldapConfig.getExtraProperties( ); + for ( Map.Entry newProp : newConfig.getProperties().entrySet() ) { + props.put( newProp.getKey( ), newProp.getValue( ) ); + } + } + + private void updateConfig(CacheConfiguration newConfig, RedbackRuntimeConfiguration rbConfig) { + org.apache.archiva.admin.model.beans.CacheConfiguration cacheConfig = rbConfig.getUsersCacheConfiguration( ); + cacheConfig.setMaxElementsInMemory( newConfig.getMaxEntriesInMemory()); + cacheConfig.setMaxElementsOnDisk( newConfig.getMaxEntriesOnDisk() ); + cacheConfig.setTimeToLiveSeconds( newConfig.getTimeToLiveSeconds() ); + cacheConfig.setTimeToIdleSeconds( newConfig.getTimeToIdleSeconds() ); + } + + @Override + public Response updateConfiguration( SecurityConfiguration newConfiguration ) throws ArchivaRestServiceException + { + try + { + RedbackRuntimeConfiguration conf = redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( ); + boolean userManagerChanged = !CollectionUtils.isEqualCollection( newConfiguration.getActiveUserManagers( ), conf.getUserManagerImpls() ); + boolean rbacManagerChanged = !CollectionUtils.isEqualCollection( newConfiguration.getActiveRbacManagers( ), conf.getRbacManagerImpls( ) ); + + boolean ldapConfigured = false; + for (String um : newConfiguration.getActiveUserManagers()) { + if (um.contains("ldap")) { + ldapConfigured=true; + } + } + if (!ldapConfigured) { + for (String rbm : newConfiguration.getActiveRbacManagers()) { + if (rbm.contains("ldap")) { + ldapConfigured = true; + } + } + } + + updateConfig( newConfiguration, conf); + redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( conf ); + + if ( userManagerChanged ) + { + log.info( "user managerImpls changed to {} so reload it", + newConfiguration.getActiveUserManagers() ); + userManager.initialize(); + } + + if ( rbacManagerChanged ) + { + log.info( "rbac manager changed to {} so reload it", + newConfiguration.getActiveRbacManagers() ); + rbacManager.initialize(); + roleManager.initialize(); + } + + if (ldapConfigured) { + try { + ldapConnectionFactory.initialize(); + } catch (Exception e) { + log.error( "Could not initialize LDAP connection factory: {}", e.getMessage( ) ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_CF_INIT_FAILED, e.getMessage() ) ); + } + } + Collection passwordRules = applicationContext.getBeansOfType( PasswordRule.class ).values(); + + for ( PasswordRule passwordRule : passwordRules ) + { + passwordRule.initialize(); + } + + Collection cookieSettingsList = + applicationContext.getBeansOfType( CookieSettings.class ).values(); + + for ( CookieSettings cookieSettings : cookieSettingsList ) + { + cookieSettings.initialize(); + } + + Collection authenticators = + applicationContext.getBeansOfType( Authenticator.class ).values(); + + for ( Authenticator authenticator : authenticators ) + { + try { + log.debug("Initializing authenticatior "+authenticator.getId()); + authenticator.initialize(); + } catch (Exception e) { + log.error("Initialization of authenticator failed "+authenticator.getId(),e); + } + } + + if (ldapConfigured) { + try { + ldapUserMapper.initialize(); + } catch (Exception e) { + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_USER_MAPPER_INIT_FAILED, e.getMessage( ) ) ); + } + } + } + catch ( RepositoryAdminException e ) + { + throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) ); + } + return Response.ok( ).build(); + } @Override public PagedResult getConfigurationProperties( String searchTerm, Integer offset, Integer limit, List orderBy, String order ) throws ArchivaRestServiceException @@ -133,6 +297,48 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio } } + @Override + public PropertyEntry getConfigurationProperty( String propertyName ) throws ArchivaRestServiceException + { + try + { + RedbackRuntimeConfiguration conf = redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( ); + if (conf.getConfigurationProperties().containsKey( propertyName )) { + String value = conf.getConfigurationProperties( ).get( propertyName ); + return new PropertyEntry( propertyName, value ); + } else { + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.PROPERTY_NOT_FOUND ), 404 ); + } + + } + catch ( RepositoryAdminException e ) + { + throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) ); + } + + } + + @Override + public Response updateConfigurationProperty( String propertyName, PropertyEntry propertyValue ) throws ArchivaRestServiceException + { + try + { + RedbackRuntimeConfiguration conf = redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( ); + if (conf.getConfigurationProperties().containsKey( propertyName )) { + conf.getConfigurationProperties( ).put( propertyName, propertyValue.getValue( ) ); + redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( conf ); + return Response.ok( ).build( ); + } else { + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.PROPERTY_NOT_FOUND ), 404 ); + } + + } + catch ( RepositoryAdminException e ) + { + throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) ); + } + } + @Override public LdapConfiguration getLdapConfiguration( ) throws ArchivaRestServiceException { @@ -152,6 +358,29 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio } + @Override + public Response updateLdapConfiguration( LdapConfiguration configuration ) throws ArchivaRestServiceException + { + try + { + RedbackRuntimeConfiguration redbackRuntimeConfiguration = + redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( ); + + log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration ); + + updateConfig( configuration, redbackRuntimeConfiguration ); + + redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( redbackRuntimeConfiguration ); + + return Response.ok( ).build( ); + + } + catch ( RepositoryAdminException e ) + { + throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) ); + } + } + @Override public CacheConfiguration getCacheConfiguration( ) throws ArchivaRestServiceException { @@ -171,6 +400,25 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio } + @Override + public Response updateCacheConfiguration( CacheConfiguration cacheConfiguration ) throws ArchivaRestServiceException + { + try + { + RedbackRuntimeConfiguration redbackRuntimeConfiguration = + redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( ); + + log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration ); + updateConfig( cacheConfiguration, redbackRuntimeConfiguration ); + redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( redbackRuntimeConfiguration ); + return Response.ok( ).build( ); + } + catch ( RepositoryAdminException e ) + { + throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) ); + } + } + @Override public List getAvailableUserManagers( ) throws ArchivaRestServiceException { diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/ErrorKeys.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/ErrorKeys.java index 85e9c5c3d..fae6bc221 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/ErrorKeys.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/ErrorKeys.java @@ -21,6 +21,10 @@ package org.apache.archiva.rest.services.v2;/* */ public interface ErrorKeys { - public static final String REPOSITORY_ADMIN_ERROR = "a.repositoryadmin.error"; + String REPOSITORY_ADMIN_ERROR = "archiva.repositoryadmin.error"; + String LDAP_CF_INIT_FAILED = "archiva.ldap.cf.init.failed"; + String LDAP_USER_MAPPER_INIT_FAILED = "archiva.ldap.usermapper.init.failed"; + + String PROPERTY_NOT_FOUND = "archiva.property.not.found"; } -- 2.39.5