diff options
15 files changed, 800 insertions, 431 deletions
diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/runtime/DefaultRedbackRuntimeConfigurationAdmin.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/runtime/DefaultRedbackRuntimeConfigurationAdmin.java index 86cad9e78..1ed25d946 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/runtime/DefaultRedbackRuntimeConfigurationAdmin.java +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/runtime/DefaultRedbackRuntimeConfigurationAdmin.java @@ -422,7 +422,6 @@ public class DefaultRedbackRuntimeConfigurationAdmin private void cleanupProperties( RedbackRuntimeConfiguration redbackRuntimeConfiguration ) { Map<String, String> properties = redbackRuntimeConfiguration.getConfigurationProperties(); - LdapConfiguration ldapConf = redbackRuntimeConfiguration.getLdapConfiguration( ); LDAP_MAPPER.getAllAttributes( ).stream( ).forEach( att -> properties.remove( att ) ); } diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/LdapConfiguration.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/LdapConfiguration.java index 378c5e234..ae789a12f 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/LdapConfiguration.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/LdapConfiguration.java @@ -20,6 +20,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import javax.xml.bind.annotation.XmlRootElement; import java.io.Serializable; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.TreeMap; @@ -36,16 +37,18 @@ public class LdapConfiguration implements Serializable private String hostName = ""; private int port = 389; - private boolean sslEnabled = false; private String baseDn = ""; private String groupsBaseDn = ""; private String bindDn = ""; private String bindPassword = ""; - private String authenticationMethod = ""; + private String authenticationMethod = "none"; + private String contextFactory; + private boolean sslEnabled = false; private boolean bindAuthenticatorEnabled = true; private boolean useRoleNameAsGroup = false; private final Map<String, String> properties = new TreeMap<>(); private boolean writable = false; + private List<String> availableContextFactories; public LdapConfiguration( ) { @@ -60,9 +63,14 @@ public class LdapConfiguration implements Serializable newCfg.setBindPassword( ldapConfiguration.getPassword() ); newCfg.setBindAuthenticatorEnabled( ldapConfiguration.isBindAuthenticatorEnabled() ); newCfg.setHostName( ldapConfiguration.getHostName( ) ); - newCfg.setPort( ldapConfiguration.getPort( ) ); - newCfg.setProperties( ldapConfiguration.getExtraProperties( ) ); newCfg.setSslEnabled( ldapConfiguration.isSsl() ); + if (ldapConfiguration.getPort()<=0) { + newCfg.setPort( newCfg.isSslEnabled() ? 636 : 389 ); + } else + { + newCfg.setPort( ldapConfiguration.getPort( ) ); + } + newCfg.setProperties( ldapConfiguration.getExtraProperties( ) ); newCfg.setWritable( ldapConfiguration.isWritable() ); return newCfg; } @@ -89,7 +97,19 @@ public class LdapConfiguration implements Serializable this.port = port; } - @Schema(name="ssl_enabled", description = "If SSL should be used for connecting the LDAP server") + @Schema(name="context_factory",description = "The class name of the LDAP context factory") + public String getContextFactory( ) + { + return contextFactory; + } + + public void setContextFactory( String contextFactory ) + { + this.contextFactory = contextFactory; + } + + + @Schema(name="ssl_enabled", description = "True, if SSL/TLS should be used for connecting the LDAP server") public boolean isSslEnabled( ) { return sslEnabled; @@ -177,7 +197,7 @@ public class LdapConfiguration implements Serializable this.useRoleNameAsGroup = useRoleNameAsGroup; } - @Schema(description = "Map of additional properties") + @Schema(description = "LDAP ConnectionFactory environment properties") public Map<String, String> getProperties( ) { return properties; @@ -200,6 +220,19 @@ public class LdapConfiguration implements Serializable this.writable = writable; } + @Schema(name="available_context_factories", description = "The LDAP context factories that are known and available") + public List<String> getAvailableContextFactories( ) + { + return availableContextFactories; + } + + public void setAvailableContextFactories( List<String> availableContextFactories ) + { + this.availableContextFactories = availableContextFactories; + } + + + @Override public boolean equals( Object o ) { 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 a8eb45919..aa02581c6 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 @@ -39,6 +39,7 @@ 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.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; @@ -240,6 +241,30 @@ public interface SecurityConfigurationService ) Response updateLdapConfiguration( LdapConfiguration configuration ) throws ArchivaRestServiceException; + @Path("config/ldap/verify") + @POST + @Consumes({ APPLICATION_JSON }) + @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION) + @Operation( summary = "Checks the given LDAP configuration.", + security = { + @SecurityRequirement( + name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION + ) + }, + responses = { + @ApiResponse( responseCode = "200", + description = "If the check was successful" + ), + @ApiResponse( responseCode = "400", + description = "If the check was not successful", + content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) + ), + @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to update the information", + content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ) + } + ) + Response verifyLdapConfiguration( LdapConfiguration configuration ) throws ArchivaRestServiceException; + @Path("config/cache") @GET @Produces({ APPLICATION_JSON }) 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 d1b4fe187..80e65c2bc 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 @@ -25,14 +25,16 @@ 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.LdapConnection; +import org.apache.archiva.redback.common.ldap.connection.LdapConnectionConfiguration; import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory; +import org.apache.archiva.redback.common.ldap.connection.LdapException; 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; import org.apache.archiva.rest.api.model.v2.CacheConfiguration; import org.apache.archiva.rest.api.model.v2.LdapConfiguration; @@ -41,7 +43,6 @@ 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; @@ -51,7 +52,12 @@ import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Named; -import javax.management.Query; +import javax.naming.AuthenticationException; +import javax.naming.AuthenticationNotSupportedException; +import javax.naming.CommunicationException; +import javax.naming.InvalidNameException; +import javax.naming.NoPermissionException; +import javax.naming.ServiceUnavailableException; import javax.ws.rs.core.Response; import java.util.ArrayList; import java.util.Collection; @@ -59,7 +65,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.Objects; +import java.util.Properties; import java.util.ResourceBundle; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -74,9 +80,14 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio { private static final Logger log = LoggerFactory.getLogger( DefaultSecurityConfigurationService.class ); + private static final String[] KNOWN_LDAP_CONTEXT_PROVIDERS = {"com.sun.jndi.ldap.LdapCtxFactory","com.ibm.jndi.LDAPCtxFactory"}; + private List<String> availableContextProviders = new ArrayList<>( ); + private static final QueryHelper<PropertyEntry> PROP_QUERY_HELPER = new QueryHelper( new String[]{"key"} ); private static final PagingHelper PROP_PAGING_HELPER = new PagingHelper( ); - static { + + static + { PROP_QUERY_HELPER.addStringFilter( "key", PropertyEntry::getKey ); PROP_QUERY_HELPER.addStringFilter( "value", PropertyEntry::getValue ); PROP_QUERY_HELPER.addNullsafeFieldComparator( "key", PropertyEntry::getKey ); @@ -94,31 +105,37 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio private ApplicationContext applicationContext; @Inject - @Named(value = "userManager#default") + @Named( value = "userManager#default" ) private UserManager userManager; @Inject - @Named(value = "rbacManager#default") + @Named( value = "rbacManager#default" ) private RBACManager rbacManager; @Inject private RoleManager roleManager; @Inject - @Named(value = "ldapConnectionFactory#configurable") + @Named( value = "ldapConnectionFactory#configurable" ) private LdapConnectionFactory ldapConnectionFactory; @Inject private LdapUserMapper ldapUserMapper; @Inject - @Named(value = "cache#users") + @Named( value = "cache#users" ) private Cache usersCache; @PostConstruct - void init() { + void init( ) + { bundle = ResourceBundle.getBundle( "org.apache.archiva.rest.RestBundle" ); + for (String ldapClass : KNOWN_LDAP_CONTEXT_PROVIDERS) { + if (isContextFactoryAvailable( ldapClass )) { + availableContextProviders.add( ldapClass ); + } + } } @Override @@ -138,128 +155,151 @@ 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() ); + + private void updateConfig( SecurityConfiguration newConfig, RedbackRuntimeConfiguration rbConfig ) + { + rbConfig.setUserManagerImpls( newConfig.getActiveUserManagers( ) ); + rbConfig.setRbacManagerImpls( newConfig.getActiveRbacManagers( ) ); + rbConfig.setUseUsersCache( newConfig.isUserCacheEnabled( ) ); Map<String, String> props = rbConfig.getConfigurationProperties( ); - for ( Map.Entry<String,String> newProp : newConfig.getProperties().entrySet() ) { + for ( Map.Entry<String, String> newProp : newConfig.getProperties( ).entrySet( ) ) + { props.put( newProp.getKey( ), newProp.getValue( ) ); } } - private void updateConfig(LdapConfiguration newConfig, RedbackRuntimeConfiguration rbConfig) { + 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.setAuthenticationMethod( newConfig.getAuthenticationMethod( ) ); ldapConfig.setBindAuthenticatorEnabled( newConfig.isBindAuthenticatorEnabled( ) ); - ldapConfig.setBindDn( newConfig.getBindDn() ); + 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.setBaseGroupsDn( newConfig.getGroupsBaseDn( ) ); + ldapConfig.setHostName( newConfig.getHostName( ) ); + ldapConfig.setPort( newConfig.getPort( ) ); + ldapConfig.setPassword( newConfig.getBindPassword( ) ); + ldapConfig.setUseRoleNameAsGroup( newConfig.isUseRoleNameAsGroup( ) ); ldapConfig.setWritable( newConfig.isWritable( ) ); Map<String, String> props = ldapConfig.getExtraProperties( ); - for ( Map.Entry<String,String> newProp : newConfig.getProperties().entrySet() ) { + for ( Map.Entry<String, String> newProp : newConfig.getProperties( ).entrySet( ) ) + { props.put( newProp.getKey( ), newProp.getValue( ) ); } } - private void updateConfig(CacheConfiguration newConfig, RedbackRuntimeConfiguration rbConfig) { + 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() ); + cacheConfig.setMaxElementsInMemory( newConfig.getMaxEntriesInMemory( ) ); + cacheConfig.setMaxElementsOnDisk( newConfig.getMaxEntriesOnDisk( ) ); + cacheConfig.setTimeToLiveSeconds( newConfig.getTimeToLiveSeconds( ) ); + cacheConfig.setTimeToIdleSeconds( newConfig.getTimeToIdleSeconds( ) ); } @Override public Response updateConfiguration( SecurityConfiguration newConfiguration ) throws ArchivaRestServiceException { - if (newConfiguration==null) { + if ( newConfiguration == null ) + { throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.MISSING_DATA ), 400 ); } try { RedbackRuntimeConfiguration conf = redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( ); - boolean userManagerChanged = !CollectionUtils.isEqualCollection( newConfiguration.getActiveUserManagers( ), conf.getUserManagerImpls() ); + 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; + for ( String um : newConfiguration.getActiveUserManagers( ) ) + { + if ( um.contains( "ldap" ) ) + { + ldapConfigured = true; } } - if (!ldapConfigured) { - for (String rbm : newConfiguration.getActiveRbacManagers()) { - if (rbm.contains("ldap")) { + if ( !ldapConfigured ) + { + for ( String rbm : newConfiguration.getActiveRbacManagers( ) ) + { + if ( rbm.contains( "ldap" ) ) + { ldapConfigured = true; } } } - updateConfig( newConfiguration, conf); + updateConfig( newConfiguration, conf ); redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( conf ); if ( userManagerChanged ) { log.info( "user managerImpls changed to {} so reload it", - newConfiguration.getActiveUserManagers() ); - userManager.initialize(); + newConfiguration.getActiveUserManagers( ) ); + userManager.initialize( ); } if ( rbacManagerChanged ) { log.info( "rbac manager changed to {} so reload it", - newConfiguration.getActiveRbacManagers() ); - rbacManager.initialize(); - roleManager.initialize(); + newConfiguration.getActiveRbacManagers( ) ); + rbacManager.initialize( ); + roleManager.initialize( ); } - if (ldapConfigured) { - try { - ldapConnectionFactory.initialize(); - } catch (Exception e) { + 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() ) ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_CF_INIT_FAILED, e.getMessage( ) ) ); } } - Collection<PasswordRule> passwordRules = applicationContext.getBeansOfType( PasswordRule.class ).values(); + Collection<PasswordRule> passwordRules = applicationContext.getBeansOfType( PasswordRule.class ).values( ); for ( PasswordRule passwordRule : passwordRules ) { - passwordRule.initialize(); + passwordRule.initialize( ); } Collection<CookieSettings> cookieSettingsList = - applicationContext.getBeansOfType( CookieSettings.class ).values(); + applicationContext.getBeansOfType( CookieSettings.class ).values( ); for ( CookieSettings cookieSettings : cookieSettingsList ) { - cookieSettings.initialize(); + cookieSettings.initialize( ); } Collection<Authenticator> authenticators = - applicationContext.getBeansOfType( Authenticator.class ).values(); + 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); + 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) { + if ( ldapConfigured ) + { + try + { + ldapUserMapper.initialize( ); + } + catch ( Exception e ) + { throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_USER_MAPPER_INIT_FAILED, e.getMessage( ) ) ); } } @@ -268,7 +308,7 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio { throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) ); } - return Response.ok( ).build(); + return Response.ok( ).build( ); } @Override @@ -306,10 +346,13 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio try { RedbackRuntimeConfiguration conf = redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( ); - if (conf.getConfigurationProperties().containsKey( propertyName )) { + if ( conf.getConfigurationProperties( ).containsKey( propertyName ) ) + { String value = conf.getConfigurationProperties( ).get( propertyName ); return new PropertyEntry( propertyName, value ); - } else { + } + else + { throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.PROPERTY_NOT_FOUND ), 404 ); } @@ -324,17 +367,21 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio @Override public Response updateConfigurationProperty( String propertyName, PropertyEntry propertyValue ) throws ArchivaRestServiceException { - if (propertyValue==null) { + if ( propertyValue == null ) + { throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.MISSING_DATA ), 400 ); } try { RedbackRuntimeConfiguration conf = redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( ); - if (conf.getConfigurationProperties().containsKey( propertyName )) { + if ( conf.getConfigurationProperties( ).containsKey( propertyName ) ) + { conf.getConfigurationProperties( ).put( propertyName, propertyValue.getValue( ) ); redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( conf ); return Response.ok( ).build( ); - } else { + } + else + { throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.PROPERTY_NOT_FOUND ), 404 ); } @@ -355,7 +402,9 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration ); - return LdapConfiguration.of( redbackRuntimeConfiguration.getLdapConfiguration() ); + LdapConfiguration ldapConfig = LdapConfiguration.of( redbackRuntimeConfiguration.getLdapConfiguration( ) ); + ldapConfig.setAvailableContextFactories( availableContextProviders ); + return ldapConfig; } catch ( RepositoryAdminException e ) { @@ -387,6 +436,123 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio } } + static final Properties toProperties( Map<String, String> values ) + { + Properties result = new Properties( ); + for ( Map.Entry<String, String> entry : values.entrySet( ) ) + { + result.setProperty( entry.getKey( ), entry.getValue( ) ); + } + return result; + } + + private static final boolean isContextFactoryAvailable(final String factoryClass) + { + try + { + return Thread.currentThread().getContextClassLoader().loadClass( factoryClass ) + != null; + } + catch ( ClassNotFoundException e ) + { + return false; + } + } + + + @Override + public Response verifyLdapConfiguration( LdapConfiguration ldapConfiguration ) throws ArchivaRestServiceException + { + LdapConnection ldapConnection = null; + try + { + LdapConnectionConfiguration ldapConnectionConfiguration = + new LdapConnectionConfiguration( ldapConfiguration.getHostName( ), ldapConfiguration.getPort( ), + ldapConfiguration.getBaseDn( ), ldapConfiguration.getContextFactory( ), + ldapConfiguration.getBindDn( ), ldapConfiguration.getBindPassword( ), + ldapConfiguration.getAuthenticationMethod( ), + toProperties( ldapConfiguration.getProperties( ) ) ); + ldapConnectionConfiguration.setSsl( ldapConfiguration.isSslEnabled( ) ); + + ldapConnection = ldapConnectionFactory.getConnection( ldapConnectionConfiguration ); + } + catch ( InvalidNameException e ) + { + log.warn( "LDAP connection check failed with invalid name : {}", e.getMessage( ), e ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_INVALID_NAME, e.getMessage( ) ), 400 ); + } + catch ( LdapException e ) + { + handleLdapException( e ); + } + finally + { + if ( ldapConnection != null ) + { + ldapConnection.close( ); + } + ldapConnection = null; + } + + try + { + // verify groups dn value too + + LdapConnectionConfiguration ldapConnectionConfiguration = new LdapConnectionConfiguration( ldapConfiguration.getHostName( ), ldapConfiguration.getPort( ), + ldapConfiguration.getGroupsBaseDn( ), + ldapConfiguration.getContextFactory( ), ldapConfiguration.getBindDn( ), + ldapConfiguration.getBindPassword( ), + ldapConfiguration.getAuthenticationMethod( ), + toProperties( ldapConfiguration.getProperties( ) ) ); + + ldapConnectionConfiguration.setSsl( ldapConfiguration.isSslEnabled( ) ); + + ldapConnection = ldapConnectionFactory.getConnection( ldapConnectionConfiguration ); + } + catch ( InvalidNameException e ) + { + log.warn( "LDAP connection check failed with invalid name : {}", e.getMessage( ), e ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_INVALID_NAME, e.getMessage( ) ), 400 ); + } + catch ( LdapException e ) + { + handleLdapException( e ); + } + finally + { + if ( ldapConnection != null ) + { + ldapConnection.close( ); + } + } + + return Response.ok( ).build( ); + } + + private void handleLdapException( LdapException e ) throws ArchivaRestServiceException + { + Throwable rootCause = e.getRootCause( ); + if ( rootCause instanceof CommunicationException ) + { + log.warn( "LDAP connection check failed with CommunicationException: {}", e.getMessage( ), e ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_COMMUNICATION_ERROR, e.getMessage( ) ), 400 ); + } else if (rootCause instanceof ServiceUnavailableException ) { + log.warn( "LDAP connection check failed with ServiceUnavailableException: {}", e.getMessage( ), e ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_SERVICE_UNAVAILABLE, e.getMessage( ) ), 400 ); + } else if (rootCause instanceof AuthenticationException ) { + log.warn( "LDAP connection check failed with AuthenticationException: {}", e.getMessage( ), e ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_SERVICE_AUTHENTICATION_FAILED, e.getMessage( ) ), 400 ); + } else if (rootCause instanceof AuthenticationNotSupportedException ) { + log.warn( "LDAP connection check failed with AuthenticationNotSupportedException: {}", e.getMessage( ), e ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_SERVICE_AUTHENTICATION_NOT_SUPPORTED, e.getMessage( ) ), 400 ); + } else if (rootCause instanceof NoPermissionException ) { + log.warn( "LDAP connection check failed with NoPermissionException: {}", e.getMessage( ), e ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_SERVICE_NO_PERMISSION, e.getMessage( ) ), 400 ); + } + log.warn( "LDAP connection check failed: {} - {}", e.getClass().getName(), e.getMessage( ), e ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_GENERIC_ERROR, e.getMessage( ) ), 400 ); + } + @Override public CacheConfiguration getCacheConfiguration( ) throws ArchivaRestServiceException { @@ -397,7 +563,7 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration ); - return CacheConfiguration.of( redbackRuntimeConfiguration.getUsersCacheConfiguration() ); + return CacheConfiguration.of( redbackRuntimeConfiguration.getUsersCacheConfiguration( ) ); } catch ( RepositoryAdminException e ) { @@ -409,7 +575,8 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio @Override public Response updateCacheConfiguration( CacheConfiguration cacheConfiguration ) throws ArchivaRestServiceException { - if (cacheConfiguration==null) { + if ( cacheConfiguration == null ) + { throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.MISSING_DATA ), 400 ); } try @@ -433,20 +600,20 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio { Map<String, UserManager> beans = applicationContext.getBeansOfType( UserManager.class ); - if ( beans.isEmpty() ) + if ( beans.isEmpty( ) ) { - return Collections.emptyList(); + return Collections.emptyList( ); } return beans.entrySet( ).stream( ) - .filter( entry -> entry.getValue().isFinalImplementation() ) - .map( (Map.Entry<String, UserManager> entry) -> { + .filter( entry -> entry.getValue( ).isFinalImplementation( ) ) + .map( ( Map.Entry<String, UserManager> entry ) -> { UserManager um = entry.getValue( ); String id = StringUtils.substringAfter( entry.getKey( ), "#" ); String displayName = bundle.getString( "user_manager." + id + ".display_name" ); String description = bundle.getString( "user_manager." + id + ".description" ); return new BeanInformation( StringUtils.substringAfter( entry.getKey( ), "#" ), displayName, um.getDescriptionKey( ), description, um.isReadOnly( ) ); - } ).collect( Collectors.toList()); + } ).collect( Collectors.toList( ) ); } @Override @@ -454,19 +621,19 @@ public class DefaultSecurityConfigurationService implements SecurityConfiguratio { Map<String, RBACManager> beans = applicationContext.getBeansOfType( RBACManager.class ); - if ( beans.isEmpty() ) + if ( beans.isEmpty( ) ) { - return Collections.emptyList(); + return Collections.emptyList( ); } return beans.entrySet( ).stream( ) - .filter( entry -> entry.getValue().isFinalImplementation() ) - .map( (Map.Entry<String, RBACManager> entry) -> { + .filter( entry -> entry.getValue( ).isFinalImplementation( ) ) + .map( ( Map.Entry<String, RBACManager> entry ) -> { RBACManager rm = entry.getValue( ); String id = StringUtils.substringAfter( entry.getKey( ), "#" ); String displayName = bundle.getString( "rbac_manager." + id + ".display_name" ); String description = bundle.getString( "rbac_manager." + id + ".description" ); return new BeanInformation( StringUtils.substringAfter( entry.getKey( ), "#" ), displayName, rm.getDescriptionKey( ), description, rm.isReadOnly( ) ); - } ).collect( Collectors.toList()); + } ).collect( Collectors.toList( ) ); } } 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 455617e09..22b8543d4 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 @@ -24,6 +24,13 @@ public interface ErrorKeys 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 LDAP_COMMUNICATION_ERROR = "archiva.ldap.communication_error"; + String LDAP_INVALID_NAME = "archiva.ldap.invalid_name"; + String LDAP_GENERIC_ERROR = "archiva.ldap.generic_error"; + String LDAP_SERVICE_UNAVAILABLE = "archiva.ldap.service_unavailable"; + String LDAP_SERVICE_AUTHENTICATION_FAILED = "archiva.ldap.authentication.failed"; + String LDAP_SERVICE_AUTHENTICATION_NOT_SUPPORTED = "archiva.ldap.authentication.not_supported"; + String LDAP_SERVICE_NO_PERMISSION = "archiva.ldap.no_permissions"; String PROPERTY_NOT_FOUND = "archiva.property.not.found"; diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeSecurityConfigurationServiceTest.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeSecurityConfigurationServiceTest.java index 02d0dc986..13b0a3e5b 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeSecurityConfigurationServiceTest.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeSecurityConfigurationServiceTest.java @@ -127,7 +127,7 @@ public class NativeSecurityConfigurationServiceTest extends AbstractNativeRestSe .then( ).statusCode( 200 ).extract( ).response( ); assertNotNull( response ); assertEquals( "", response.getBody( ).jsonPath( ).get( "host_name" ) ); - assertEquals( 13, response.getBody( ).jsonPath( ).getMap( "properties" ).size( ) ); + assertEquals( 0, response.getBody( ).jsonPath( ).getMap( "properties" ).size( ) ); } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/package-lock.json b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/package-lock.json index 4c3d50efd..d668ec0df 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/package-lock.json +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/package-lock.json @@ -5,25 +5,25 @@ "requires": true, "dependencies": { "@angular-devkit/architect": { - "version": "0.1100.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1100.2.tgz", - "integrity": "sha512-wSMMM8eBPol48OtvIyrIq2H9rOIiJmrPEtPbH0BSuPX0B8BckVImeTPzloqxSrpul4tY7Iwx0zwISDEgb59Vbw==", + "version": "0.1100.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1100.6.tgz", + "integrity": "sha512-4O+cg3AimI2bNAxxdu5NrqSf4Oa8r8xL0+G2Ycd3jLoFv0h0ecJiNKEG5F6IpTprb4aexZD6pcxBJCqQ8MmzWQ==", "dev": true, "requires": { - "@angular-devkit/core": "11.0.2", + "@angular-devkit/core": "11.0.6", "rxjs": "6.6.3" } }, "@angular-devkit/build-angular": { - "version": "0.1100.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1100.2.tgz", - "integrity": "sha512-5Qo3DDKggzUJKibNgeyE5mIMFYP0tVebNvMatpbnYnR/U0fUuuQdvNC68s380M5KoOuubfeXr0Js0VFk0mkaow==", + "version": "0.1100.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1100.6.tgz", + "integrity": "sha512-HcqsWiSIUxExGg3HRQScLOmF+ckVkCKolfpPcNOCCpBYxH/i8n4wDGLBP5Rtxky+0Qz+3nnAaFIpNb9p9aUmbg==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1100.2", - "@angular-devkit/build-optimizer": "0.1100.2", - "@angular-devkit/build-webpack": "0.1100.2", - "@angular-devkit/core": "11.0.2", + "@angular-devkit/architect": "0.1100.6", + "@angular-devkit/build-optimizer": "0.1100.6", + "@angular-devkit/build-webpack": "0.1100.6", + "@angular-devkit/core": "11.0.6", "@babel/core": "7.12.3", "@babel/generator": "7.12.1", "@babel/plugin-transform-runtime": "7.12.1", @@ -31,7 +31,7 @@ "@babel/runtime": "7.12.1", "@babel/template": "7.10.4", "@jsdevtools/coverage-istanbul-loader": "3.0.5", - "@ngtools/webpack": "11.0.2", + "@ngtools/webpack": "11.0.6", "ansi-colors": "4.1.1", "autoprefixer": "9.8.6", "babel-loader": "8.1.0", @@ -77,7 +77,7 @@ "speed-measure-webpack-plugin": "1.3.3", "style-loader": "2.0.0", "stylus": "0.54.8", - "stylus-loader": "4.1.1", + "stylus-loader": "4.3.1", "terser": "5.3.7", "terser-webpack-plugin": "4.2.3", "text-table": "0.2.0", @@ -100,9 +100,9 @@ } }, "@angular-devkit/build-optimizer": { - "version": "0.1100.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1100.2.tgz", - "integrity": "sha512-2ZdEeAs0a53g9LDkP5H2mCEPLyk7yd9P7eTepNYvIOz3xJ6W6dB2CqotPMfnHgd4o12cbzCOWrPBxbfo/VnMig==", + "version": "0.1100.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1100.6.tgz", + "integrity": "sha512-Qkq7n6510N+nXmfZqpqpI0I6Td+b+06RRNmS7KftSNJntU1z5QYh4FggwlthZ5P0QUT92cnBQsnT8OgYqGnwbg==", "dev": true, "requires": { "loader-utils": "2.0.0", @@ -121,20 +121,20 @@ } }, "@angular-devkit/build-webpack": { - "version": "0.1100.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1100.2.tgz", - "integrity": "sha512-XVMtWoxNa3wJLRjJ846Y02PzupdbUizdAtggRu2731RLMvI1KawWlsTURi12MNUnoVQYm9eldiIA/Y1UqeE8mQ==", + "version": "0.1100.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1100.6.tgz", + "integrity": "sha512-kK0FlpYJHP25o1yzIGHQqIvO5kp+p6V5OwGpD2GGRZLlJqd3WdjY5DxnyZoX3/IofO6KsTnmm76fzTRqc62z/Q==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1100.2", - "@angular-devkit/core": "11.0.2", + "@angular-devkit/architect": "0.1100.6", + "@angular-devkit/core": "11.0.6", "rxjs": "6.6.3" } }, "@angular-devkit/core": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.2.tgz", - "integrity": "sha512-vUmmUNmNM9oRcDmt0PunU/ayglo0apq4pGL9Z5jj6alf2WwEiTcGHjyuZSDIO9MOLi41519jp3mDx79qXvvyww==", + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.6.tgz", + "integrity": "sha512-nhvU5hH01r9qcexAqvIFU233treWWeW3ncs9UFYjD9Hys9sDSvqC3+bvGvl9vCG5FsyY7oDsjaVAipyUc+SFAg==", "dev": true, "requires": { "ajv": "6.12.6", @@ -159,20 +159,20 @@ } }, "@angular-devkit/schematics": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.0.2.tgz", - "integrity": "sha512-unNewc+Y9ofrdKxXNoSHKUL6wvV8Vgh2nJMTLI1VAw8nfqgWphI+s5XwbVzog65nhZ10xJeaUm9u5R8pxLDpQg==", + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.0.6.tgz", + "integrity": "sha512-hCyu/SSSiC6dKl/NxdWctknIrBqKR6pRe7DMArWowrZX6P9oi36LpKEFnKutE8+tXjsOqQj8XMBq9L64sXZWqg==", "dev": true, "requires": { - "@angular-devkit/core": "11.0.2", + "@angular-devkit/core": "11.0.6", "ora": "5.1.0", "rxjs": "6.6.3" } }, "@angular/animations": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-11.0.2.tgz", - "integrity": "sha512-uF/RlBY1rznbuw+1lm8Q2HKDrBOQQ2Bi2cUPuef+ALn+lxGl501eHlE+PTtBjDEzJcJPfd4pE3Ww3+3Il+D+Tw==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-11.0.7.tgz", + "integrity": "sha512-P3cluDGIsaj7vqvqIGW7xFCIXWa1lJDsHsmY3Fexk+ZVCncokftp5ZUANb2+DwOD3BPgd/WjBdXVjwzFQFsoVA==", "requires": { "tslib": "^2.0.0" } @@ -195,20 +195,20 @@ } }, "@angular/cli": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-11.0.2.tgz", - "integrity": "sha512-mebt4ikwXD3gsbHRxKCpn83yW3UVnhiVDEpSXljs1YxscZ1X1dXrxb2g6LdAJwVp9xY5ERqRQeZM7eChqLTrvg==", + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-11.0.6.tgz", + "integrity": "sha512-bwrXXyU23HjUlFl0CNCU+XMGa/enooqpMLcTAA15StVpKFHyaA4c57il/aqu+1IuB+zR6rGDzhAABuvRcHd+mQ==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1100.2", - "@angular-devkit/core": "11.0.2", - "@angular-devkit/schematics": "11.0.2", - "@schematics/angular": "11.0.2", - "@schematics/update": "0.1100.2", + "@angular-devkit/architect": "0.1100.6", + "@angular-devkit/core": "11.0.6", + "@angular-devkit/schematics": "11.0.6", + "@schematics/angular": "11.0.6", + "@schematics/update": "0.1100.6", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.1", "debug": "4.2.0", - "ini": "1.3.5", + "ini": "1.3.6", "inquirer": "7.3.3", "npm-package-arg": "8.1.0", "npm-pick-manifest": "6.1.0", @@ -231,6 +231,12 @@ "ms": "2.1.2" } }, + "ini": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.6.tgz", + "integrity": "sha512-IZUoxEjNjubzrmvzZU4lKP7OnYmX72XRl3sqkfJhBKweKi5rnGi5+IUdlj/H1M+Ip5JQ1WzaDMOBRY90Ajc5jg==", + "dev": true + }, "resolve": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", @@ -250,25 +256,25 @@ } }, "@angular/common": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-11.0.2.tgz", - "integrity": "sha512-DGJuSBDt+bF77AzJNrLzeaFGSdwQ3OjgP9UUv1eKvaxp9D+lDam8suIJMuBwTsJII/yrDndY75ENPNTEqhmB2A==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-11.0.7.tgz", + "integrity": "sha512-9VuT9qrSP7Q91Wp276DDieCIZiTBrpLNoJzK/RygQShTymCVPg4Dsl3tQUKaHBPx9MexeqRG/HjN02DVpeqtsA==", "requires": { "tslib": "^2.0.0" } }, "@angular/compiler": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-11.0.2.tgz", - "integrity": "sha512-deDT5+Lcph4nNhh6sZd0mBS5OkJL3HPbX5upDMI28Wuayt18Pn0UNotWY77/KV6wwIAInmlx9N06PoH3pq3hqg==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-11.0.7.tgz", + "integrity": "sha512-U+aGn6lP3iB184D2Z+OSK5vCwNtxtsF59T7nNJBMCCwcN7Qc5tfDBbSj1GI11XrIiuuoOxXbAp9BKS0dAyNCWw==", "requires": { "tslib": "^2.0.0" } }, "@angular/compiler-cli": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-11.0.2.tgz", - "integrity": "sha512-I39zNcf6q0NN4PKCbY6Lm4WP69ujLrAew56X5yvlECW9CJlidV0qi1S/DGgAWhXTDOt8XA/KP1hD1pgJtMHjJQ==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-11.0.7.tgz", + "integrity": "sha512-04agqIPmw1exMeZjJmRzeYFgTEXYJ7gKD8TZipsGlu99uU/NQJIsetpzR7/bhPAKDH6YO0p/uavxV0nRpSTIQw==", "dev": true, "requires": { "@babel/core": "^7.8.6", @@ -368,9 +374,9 @@ "dev": true }, "yargs": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.1.tgz", - "integrity": "sha512-hAD1RcFP/wfgfxgMVswPE+z3tlPFtxG8/yWUrG2i17sTWGCGqWnxKcLTF4cUKDUK8fzokwsmO9H0TDkRbMHy8w==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -391,25 +397,25 @@ } }, "@angular/core": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-11.0.2.tgz", - "integrity": "sha512-GyDebks5ZPHDyChDW3VvzJq00Ct0iuesNpb9z/GpKtOXqug3sGr4KgkFDUTbfizKPWyeoaLH9FQYP55215nCKQ==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-11.0.7.tgz", + "integrity": "sha512-Kj5uRZoK5+xfMTjkP3tw8oIF5hKTnoF9Bwh5m9GUKqg1wHVKOJcT5JBIEMc8qPyiFgALREA01reIzQdGMjX36A==", "requires": { "tslib": "^2.0.0" } }, "@angular/forms": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-11.0.2.tgz", - "integrity": "sha512-Rn17VPviTTwiDn8Yt/UzdkXjFX0LdvjkmTNZoakqOk8/QNnsCG5sUDJAV7BKHk+2nEfUGCopS4kpBiLKLoaBpQ==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-11.0.7.tgz", + "integrity": "sha512-+3A+SciMyHTdUwkKUz4XzC1DSYexQEbFLe0PKQIFSFOROmbssjnWJv7yO2HbzCpGa7oGKPYNlE5twYWyLxpvFg==", "requires": { "tslib": "^2.0.0" } }, "@angular/localize": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-11.0.2.tgz", - "integrity": "sha512-G7v/WPjno5QgY2XvYqK9pKP5lsaE17rP6/FIYhTFoA2TTSTJQ0mWlIQigcTvr+AT2t4U6nFJeteGuyIIvpMJYg==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-11.0.7.tgz", + "integrity": "sha512-NDs08oAELLn7tA/hHLuW8APULg25C7iINYTA168QzOdFTEsJ2MoLf3SiVQExUV65h3MnB24xNbhaNodmBKUNPg==", "dev": true, "requires": { "@babel/core": "7.8.3", @@ -534,9 +540,9 @@ "dev": true }, "yargs": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.1.tgz", - "integrity": "sha512-hAD1RcFP/wfgfxgMVswPE+z3tlPFtxG8/yWUrG2i17sTWGCGqWnxKcLTF4cUKDUK8fzokwsmO9H0TDkRbMHy8w==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -557,33 +563,33 @@ } }, "@angular/platform-browser": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-11.0.2.tgz", - "integrity": "sha512-RHPm5/h8g3lSBgdg9OvO7w06juEwwBurvQcugXlk7+AeqznwzBodTWGPIATKzMySXQFmpy3bAZ3IxS0NkRrbWA==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-11.0.7.tgz", + "integrity": "sha512-W8Wt8jMUjcbpqGtqrNWAj0p7CLdjOxgVlbrgBXTbaoqdchvXH85YzGr7ohA3MuE61H90OcVK9OhfYQk5o6joSg==", "requires": { "tslib": "^2.0.0" } }, "@angular/platform-browser-dynamic": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.0.2.tgz", - "integrity": "sha512-iV7xz90FdmYFiXZRLkZtP9Lr+OXXh4bhkX7zN1L5H8SSUF4iOJGBdOts5Fiy5GZjYYILjF1pJoEIicfW/RSHjA==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.0.7.tgz", + "integrity": "sha512-pUXCum1Z2DZV/34WR4Vfmkc5nWxbmVdwAA9pXbAarwAYqHIqOzX8rpRaHsuHBAR+SK+VH+xjproeLgsVfV8FSA==", "requires": { "tslib": "^2.0.0" } }, "@angular/router": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-11.0.2.tgz", - "integrity": "sha512-EU0lQ+3vv1ozly+Z4SgaGj/6CWMIExjnSnA1F7SI2yWmMgMMSb5CsGJ2xzr0V8ex3XZzuU2VuKF74muC58qSyg==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-11.0.7.tgz", + "integrity": "sha512-oh/MOPRSOCLRPsM/3CVUNYZ3pz3g+CzLOk5Vad/zFJmnGwjA/lQGJo2pl7VXVq3RF7MieaHlDWG5TexGlXAP5w==", "requires": { "tslib": "^2.0.0" } }, "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { "@babel/highlight": "^7.10.4" @@ -653,12 +659,12 @@ } }, "@babel/helper-annotate-as-pure": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", - "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz", + "integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.12.10" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { @@ -712,22 +718,6 @@ "requires": { "@babel/helper-annotate-as-pure": "^7.10.4", "regexpu-core": "^4.7.1" - }, - "dependencies": { - "regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" - } - } } }, "@babel/helper-define-map": { @@ -751,23 +741,36 @@ } }, "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", - "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", + "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-get-function-arity": "^7.12.10", + "@babel/template": "^7.12.7", + "@babel/types": "^7.12.11" + }, + "dependencies": { + "@babel/template": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", + "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7" + } + } } }, "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", - "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", + "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.12.10" } }, "@babel/helper-hoist-variables": { @@ -815,12 +818,12 @@ } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz", - "integrity": "sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", + "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", "dev": true, "requires": { - "@babel/types": "^7.12.7" + "@babel/types": "^7.12.10" } }, "@babel/helper-plugin-utils": { @@ -841,15 +844,15 @@ } }, "@babel/helper-replace-supers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", - "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz", + "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/helper-member-expression-to-functions": "^7.12.7", + "@babel/helper-optimise-call-expression": "^7.12.10", + "@babel/traverse": "^7.12.10", + "@babel/types": "^7.12.11" } }, "@babel/helper-simple-access": { @@ -871,24 +874,24 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", - "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", + "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", "dev": true, "requires": { - "@babel/types": "^7.11.0" + "@babel/types": "^7.12.11" } }, "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz", - "integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz", + "integrity": "sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==", "dev": true }, "@babel/helper-wrap-function": { @@ -926,15 +929,15 @@ } }, "@babel/parser": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz", - "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", + "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", "dev": true }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz", - "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==", + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.12.tgz", + "integrity": "sha512-nrz9y0a4xmUrRq51bYkWJIO5SBZyG2ys2qinHsN0zHDHVsUaModrkpyWWWXfGqYQmOL3x9sQIcTNN/pBGpo09A==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", @@ -1202,9 +1205,9 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz", - "integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==", + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.12.tgz", + "integrity": "sha512-VOEPQ/ExOVqbukuP7BYJtI5ZxxsmegTwzZ04j1aF0dkSypGo9XpDHuOrABsJu+ie+penpSJheDJ11x1BEZNiyQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" @@ -1478,9 +1481,9 @@ } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz", - "integrity": "sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz", + "integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" @@ -1631,29 +1634,29 @@ } }, "@babel/traverse": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz", - "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==", + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", + "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.7", - "@babel/types": "^7.12.7", + "@babel/code-frame": "^7.12.11", + "@babel/generator": "^7.12.11", + "@babel/helper-function-name": "^7.12.11", + "@babel/helper-split-export-declaration": "^7.12.11", + "@babel/parser": "^7.12.11", + "@babel/types": "^7.12.12", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" }, "dependencies": { "@babel/generator": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", - "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", + "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", "dev": true, "requires": { - "@babel/types": "^7.12.5", + "@babel/types": "^7.12.11", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -1667,32 +1670,32 @@ } }, "@babel/types": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz", - "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==", + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", + "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", "to-fast-properties": "^2.0.0" } }, "@fortawesome/fontawesome-common-types": { - "version": "0.2.29", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.29.tgz", - "integrity": "sha512-cY+QfDTbZ7XVxzx7jxbC98Oxr/zc7R2QpTLqTxqlfyXDrAJjzi/xUIqAUsygELB62JIrbsWxtSRhayKFkGI7MA==" + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.32.tgz", + "integrity": "sha512-ux2EDjKMpcdHBVLi/eWZynnPxs0BtFVXJkgHIxXRl+9ZFaHPvYamAfCzeeQFqHRjuJtX90wVnMRaMQAAlctz3w==" }, "@fortawesome/fontawesome-free": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.13.1.tgz", - "integrity": "sha512-D819f34FLHeBN/4xvw0HR0u7U2G7RqjPSggXqf7LktsxWQ48VAfGwvMrhcVuaZV2fF069c/619RdgCCms0DHhw==" + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.1.tgz", + "integrity": "sha512-OEdH7SyC1suTdhBGW91/zBfR6qaIhThbcN8PUXtXilY4GYnSBbVqOntdHbC1vXwsDnX0Qix2m2+DSU1J51ybOQ==" }, "@fortawesome/fontawesome-svg-core": { - "version": "1.2.29", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.29.tgz", - "integrity": "sha512-xmPmP2t8qrdo8RyKihTkGb09RnZoc+7HFBCnr0/6ZhStdGDSLeEd7ajV181+2W29NWIFfylO13rU+s3fpy3cnA==", + "version": "1.2.32", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.32.tgz", + "integrity": "sha512-XjqyeLCsR/c/usUpdWcOdVtWFVjPbDFBTQkn2fQRrWhhUoxriQohO2RWDxLyUM8XpD+Zzg5xwJ8gqTYGDLeGaQ==", "requires": { - "@fortawesome/fontawesome-common-types": "^0.2.29" + "@fortawesome/fontawesome-common-types": "^0.2.32" } }, "@istanbuljs/schema": { @@ -1715,20 +1718,20 @@ } }, "@ng-bootstrap/ng-bootstrap": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-8.0.0.tgz", - "integrity": "sha512-v77Gfd8xHH+exq0WqIqVRlxbUEHdA/2+RUJenUP2IDTQN9E1rWl7O461/kosr+0XPuxPArHQJxhh/WsCYckcNg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-8.0.1.tgz", + "integrity": "sha512-v/TyLbXOguEGiV1SuNzHoBeahGwCihBcB96LJz91DexPbM403jiLNxhoFtEYbAPRoPI9v3MILxSgOwCkdyeBVw==", "requires": { "tslib": "^2.0.0" } }, "@ngtools/webpack": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-11.0.2.tgz", - "integrity": "sha512-GbNP6HMBVoee2CkYW/pknprFCeiOLz4FGE06yr4m0700c1i6wuX7AzyHfBcLGAIP6nVblNOT3eh5M41b3cDf8g==", + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-11.0.6.tgz", + "integrity": "sha512-vf5YNEpXWRa0fKC/BRq5sVVj2WnEqW8jn14YQRHwVt5ppUeyu8IKUF69p6W1MwZMgMqMaw/vPQ8LI5cFbyf3uw==", "dev": true, "requires": { - "@angular-devkit/core": "11.0.2", + "@angular-devkit/core": "11.0.6", "enhanced-resolve": "5.3.1", "webpack-sources": "2.0.1" } @@ -1750,28 +1753,28 @@ } }, "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.3", + "@nodelib/fs.stat": "2.0.4", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.4", "fastq": "^1.6.0" } }, @@ -1793,30 +1796,38 @@ } }, "@schematics/angular": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-11.0.2.tgz", - "integrity": "sha512-tUIuCYJUzHYuiXGJ2KCuwxMocS56kPHaM8+neVYWwWbOxKzLZXv80gMm/pIWxrqUDCkIUi3yb4ienudFhgQLYg==", + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-11.0.6.tgz", + "integrity": "sha512-XUcpOrlcp55PBHrgpIVx69lnhDY6ro35BSRmqNmjXik56qcOkfvdki8vvyW9EsWvu9/sfBSsVDdparlbVois7w==", "dev": true, "requires": { - "@angular-devkit/core": "11.0.2", - "@angular-devkit/schematics": "11.0.2", + "@angular-devkit/core": "11.0.6", + "@angular-devkit/schematics": "11.0.6", "jsonc-parser": "2.3.1" } }, "@schematics/update": { - "version": "0.1100.2", - "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1100.2.tgz", - "integrity": "sha512-pETCmQylIQ7RM+8uqDkI3KfOaX5H7nuzmMXby28zdLPMZniYti0gJxieiVFhvdz2Ot2Axj0hznfmraFgC9mQMw==", + "version": "0.1100.6", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1100.6.tgz", + "integrity": "sha512-+B8n+k+zZ3VYOhjNBsLqzjp8O9ZdUWgdpf9L8XAA7mh/oPwufXpExyEc66uAS07imvUMmjz6i8E2eNWV/IjBJg==", "dev": true, "requires": { - "@angular-devkit/core": "11.0.2", - "@angular-devkit/schematics": "11.0.2", + "@angular-devkit/core": "11.0.6", + "@angular-devkit/schematics": "11.0.6", "@yarnpkg/lockfile": "1.1.0", - "ini": "1.3.5", + "ini": "1.3.6", "npm-package-arg": "^8.0.0", "pacote": "9.5.12", "semver": "7.3.2", "semver-intersect": "1.4.0" + }, + "dependencies": { + "ini": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.6.tgz", + "integrity": "sha512-IZUoxEjNjubzrmvzZU4lKP7OnYmX72XRl3sqkfJhBKweKi5rnGi5+IUdlj/H1M+Ip5JQ1WzaDMOBRY90Ajc5jg==", + "dev": true + } } }, "@types/color-name": { @@ -1863,9 +1874,9 @@ "dev": true }, "@types/node": { - "version": "12.12.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.47.tgz", - "integrity": "sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A==", + "version": "12.19.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.12.tgz", + "integrity": "sha512-UwfL2uIU9arX/+/PRcIkT08/iBadGN2z6ExOROA2Dh5mAuWTBj6iJbQX4nekiV5H8cTrEG569LeX+HRco9Cbxw==", "dev": true }, "@types/parse-json": { @@ -2773,9 +2784,9 @@ "dev": true }, "bootstrap": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.0.tgz", - "integrity": "sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA==" + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.3.tgz", + "integrity": "sha512-o9ppKQioXGqhw8Z7mah6KdTYpNQY//tipnkxppWhPbiSWdD+1raYsnhwEZjkTHYbGee4cVQ0Rx65EhOY/HNLcQ==" }, "brace-expansion": { "version": "1.1.11", @@ -2895,16 +2906,16 @@ } }, "browserslist": { - "version": "4.14.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.7.tgz", - "integrity": "sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz", + "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001157", + "caniuse-lite": "^1.0.30001173", "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.591", + "electron-to-chromium": "^1.3.634", "escalade": "^3.1.1", - "node-releases": "^1.1.66" + "node-releases": "^1.1.69" } }, "browserstack": { @@ -3020,13 +3031,13 @@ } }, "call-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", - "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.1.tgz", + "integrity": "sha512-tvAvUwNcRikl3RVF20X9lsYmmepsovzTWeJiXjO0PkJp15uy/6xKFZOQtuiSULwYW+6ToZBprphCgWXC2dSgcQ==", "dev": true, "requires": { "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.0" + "get-intrinsic": "^1.0.2" } }, "caller-callsite": { @@ -3078,9 +3089,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001161", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001161.tgz", - "integrity": "sha512-JharrCDxOqPLBULF9/SPa6yMcBRTjZARJ6sc3cuKrPfyIk64JN6kuMINWqA99Xc8uElMFcROliwtz0n9pYej+g==", + "version": "1.0.30001173", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001173.tgz", + "integrity": "sha512-R3aqmjrICdGCTAnSXtNyvWYMK3YtV5jwudbq0T7nN9k4kmE4CBuwPqyJ+KBzepSTh0huivV2gLbSMEzTTmfeYw==", "dev": true }, "canonical-path": { @@ -3297,9 +3308,9 @@ } }, "codelyzer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.0.tgz", - "integrity": "sha512-edJIQCIcxD9DhVSyBEdJ38AbLikm515Wl91t5RDGNT88uA6uQdTm4phTWfn9JhzAI8kXNUcfYyAE90lJElpGtA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.1.tgz", + "integrity": "sha512-cOyGQgMdhnRYtW2xrJUNrNYDjEgwQ+BrE2y93Bwz3h4DJ6vJRLfupemU5N3pbYsUlBHJf0u1j1UGk+NLW4d97g==", "dev": true, "requires": { "@angular/compiler": "9.0.0", @@ -3343,9 +3354,15 @@ "dev": true }, "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "zone.js": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", + "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==", "dev": true } } @@ -3704,12 +3721,12 @@ "dev": true }, "core-js-compat": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.0.tgz", - "integrity": "sha512-o9QKelQSxQMYWHXc/Gc4L8bx/4F7TTraE5rhuN8I7mKBt5dBIUpXpIR3omv70ebr8ST5R3PqbDQr+ZI3+Tt1FQ==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.2.tgz", + "integrity": "sha512-LO8uL9lOIyRRrQmZxHZFl1RV+ZbcsAkFWTktn5SmH40WgLtSNYN4m4W2v9ONT147PxBY/XrRhrWq8TlvObyUjQ==", "dev": true, "requires": { - "browserslist": "^4.14.7", + "browserslist": "^4.16.0", "semver": "7.0.0" }, "dependencies": { @@ -3922,14 +3939,13 @@ "dev": true }, "css-selector-tokenizer": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.2.tgz", - "integrity": "sha512-yj856NGuAymN6r8bn8/Jl46pR+OC3eEvAhfGYDUe7YPtTPAYrSSw4oAniZ9Y8T5B92hjhwTBLUen0/vKPxf6pw==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", + "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", "dev": true, "requires": { "cssesc": "^3.0.0", - "fastparse": "^1.1.2", - "regexpu-core": "^4.6.0" + "fastparse": "^1.1.2" } }, "css-tree": { @@ -4423,9 +4439,9 @@ }, "dependencies": { "domelementtype": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", - "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", "dev": true } } @@ -4490,9 +4506,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.610", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.610.tgz", - "integrity": "sha512-eFDC+yVQpEhtlapk4CYDPfV9ajF9cEof5TBcO49L1ETO+aYogrKWDmYpZyxBScMNe8Bo/gJamH4amQ4yyvXg4g==", + "version": "1.3.635", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.635.tgz", + "integrity": "sha512-RRriZOLs9CpW6KTLmgBqyUdnY0QNqqWs0HOtuQGGEMizOTNNn1P7sGRBxARnUeLejOsgwjDyRqT3E/CSst02ZQ==", "dev": true }, "elliptic": { @@ -4692,9 +4708,9 @@ "dev": true }, "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "requires": { "prr": "~1.0.1" @@ -5184,9 +5200,9 @@ "dev": true }, "fastq": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", - "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.0.tgz", + "integrity": "sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -5523,9 +5539,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", - "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", + "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -5587,9 +5603,9 @@ "dev": true }, "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", + "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -5830,9 +5846,9 @@ "dev": true }, "html-entities": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz", - "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", + "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", "dev": true }, "html-escaper": { @@ -6348,10 +6364,13 @@ } }, "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } }, "is-arrayish": { "version": "0.2.1", @@ -6494,9 +6513,9 @@ "dev": true }, "is-negative-zero": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", "dev": true }, "is-number": { @@ -6829,9 +6848,9 @@ "dev": true }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -8061,9 +8080,9 @@ } }, "node-releases": { - "version": "1.1.67", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz", - "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==", + "version": "1.1.69", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.69.tgz", + "integrity": "sha512-DGIjo79VDEyAnRlfSqYTsy+yoHd2IOjJiKUozD2MV2D85Vso6Bug56mb9tT/fY5Urt0iqk01H7x+llAruDR2zA==", "dev": true }, "normalize-package-data": { @@ -8303,9 +8322,9 @@ } }, "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", "dev": true }, "object-is": { @@ -9226,9 +9245,9 @@ } }, "import-fresh": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", - "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -10362,9 +10381,9 @@ "dev": true }, "regenerate": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", - "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true }, "regenerate-unicode-properties": { @@ -10439,9 +10458,9 @@ } }, "regexpu-core": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", - "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", "dev": true, "requires": { "regenerate": "^1.4.0", @@ -10540,11 +10559,12 @@ "dev": true }, "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", "dev": true, "requires": { + "is-core-module": "^2.1.0", "path-parse": "^1.0.6" } }, @@ -12052,9 +12072,9 @@ } }, "stylus-loader": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-4.1.1.tgz", - "integrity": "sha512-Vnm7J/nIs/P6swIrdwJW/dflhsCOiFmb1U3PeQ6phRtg1soPLN4uKnnL7AtGIJDe173elbtYIXVzmCyF493CfA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-4.3.1.tgz", + "integrity": "sha512-apDYJEM5ZpOAWbWInWcsbtI8gHNr/XYVcSY/tWqOUPt7M5tqhtwXVsAkgyiVjhuvw2Yrjq474a9H+g4d047Ebw==", "dev": true, "requires": { "fast-glob": "^3.2.4", @@ -12126,15 +12146,15 @@ "dev": true }, "tapable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.1.1.tgz", - "integrity": "sha512-Wib1S8m2wdpLbmQz0RBEVosIyvb/ykfKXf3ZIDqvWoMg/zTNm6G/tDSuUM61J1kNCDXWJrLHGSFeMhAG+gAGpQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", + "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", "dev": true }, "tar": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", - "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", "dev": true, "requires": { "chownr": "^2.0.0", @@ -12384,14 +12404,14 @@ "dev": true }, "tslib": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.0.tgz", - "integrity": "sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" }, "tslint": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.2.tgz", - "integrity": "sha512-UyNrLdK3E0fQG/xWNqAFAC5ugtFyPO4JJR1KyyfQAyzR8W0fTRrC91A8Wej4BntFzcvETdCSDa/4PnNYJQLYiA==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -12405,7 +12425,7 @@ "mkdirp": "^0.5.3", "resolve": "^1.3.2", "semver": "^5.3.0", - "tslib": "^1.10.0", + "tslib": "^1.13.0", "tsutils": "^2.29.0" }, "dependencies": { @@ -12416,9 +12436,9 @@ "dev": true }, "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true } } @@ -12433,9 +12453,9 @@ }, "dependencies": { "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true } } @@ -13425,9 +13445,9 @@ }, "dependencies": { "mime": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.7.tgz", + "integrity": "sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==", "dev": true } } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/package.json b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/package.json index 06b66662a..d4445e55c 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/package.json +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/package.json @@ -11,21 +11,21 @@ }, "private": true, "dependencies": { - "@angular/animations": "~11.0.2", + "@angular/animations": "^11.0.7", "@angular/cdk": "^11.0.3", - "@angular/common": "~11.0.2", - "@angular/compiler": "~11.0.2", - "@angular/core": "~11.0.2", - "@angular/forms": "~11.0.2", - "@angular/platform-browser": "~11.0.2", - "@angular/platform-browser-dynamic": "~11.0.2", - "@angular/router": "~11.0.2", - "@fortawesome/fontawesome-free": "^5.13.1", - "@fortawesome/fontawesome-svg-core": "^1.2.29", - "@ng-bootstrap/ng-bootstrap": "^8.0.0", + "@angular/common": "^11.0.7", + "@angular/compiler": "^11.0.7", + "@angular/core": "^11.0.7", + "@angular/forms": "^11.0.7", + "@angular/platform-browser": "^11.0.7", + "@angular/platform-browser-dynamic": "^11.0.7", + "@angular/router": "^11.0.7", + "@fortawesome/fontawesome-free": "^5.15.1", + "@fortawesome/fontawesome-svg-core": "^1.2.32", + "@ng-bootstrap/ng-bootstrap": "^8.0.1", "@ngx-translate/core": "^13.0.0", "@ngx-translate/http-loader": "^6.0.0", - "bootstrap": "^4.5.0", + "bootstrap": "^4.5.3", "flag-icon-css": "^3.5.0", "jquery": "^3.5.1", "messageformat": "^2.3.0", @@ -33,18 +33,18 @@ "popper.js": "^1.16.1", "rxjs": "~6.6.3", "service": "^0.1.4", - "tslib": "^2.0.0", - "zone.js": "~0.10.3" + "tslib": "^2.1.0", + "zone.js": "^0.10.3" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.1100.2", - "@angular/cli": "~11.0.2", - "@angular/compiler-cli": "~11.0.2", - "@angular/localize": "^11.0.2", + "@angular-devkit/build-angular": "^0.1100.6", + "@angular/cli": "^11.0.6", + "@angular/compiler-cli": "^11.0.7", + "@angular/localize": "^11.0.7", "@types/jasmine": "~3.6.0", "@types/jasminewd2": "~2.0.3", - "@types/node": "^12.11.1", - "codelyzer": "^6.0.0", + "@types/node": "^12.19.12", + "codelyzer": "^6.0.1", "jasmine-core": "~3.6.0", "jasmine-spec-reporter": "~5.0.0", "karma": "~5.1.1", @@ -54,7 +54,7 @@ "karma-jasmine-html-reporter": "^1.5.0", "protractor": "~7.0.0", "ts-node": "~8.3.0", - "tslint": "~6.1.0", + "tslint": "^6.1.3", "typescript": "~4.0.5" } } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.ts index 94b64369c..eb01950c2 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.ts @@ -18,8 +18,9 @@ export class LdapConfiguration { host_name : string = ""; - port : number = -1; + port : number = 389; ssl_enabled : boolean = false; + context_factory: string = ""; base_dn : string = ""; groups_base_dn : string = ""; bind_dn : string = ""; @@ -29,4 +30,5 @@ export class LdapConfiguration { use_role_name_as_group : boolean = false; properties : Map<string,string> = new Map<string, string>() writable : boolean = false; + available_context_factories : string[]; } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/http-error-interceptor.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/http-error-interceptor.ts index a4ebbd5a8..78fe8fb3e 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/http-error-interceptor.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/core/errors/http-error-interceptor.ts @@ -41,6 +41,9 @@ export class HttpErrorInterceptor implements HttpInterceptor { ): Observable<HttpEvent<any>> { return next.handle(request).pipe( catchError((error: HttpErrorResponse) => { + if (error.url.includes('security/config/ldap/verify')) { + return throwError(error); + } console.error("Error from HTTP error interceptor", error); if (error.status==0 && error.statusText=="Unknown Error") { console.log("Unknown error"); diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.html index e98239894..c6850e330 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.html +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.html @@ -18,7 +18,7 @@ <form class="mt-3 mb-3" [formGroup]="userForm" (ngSubmit)="onSubmit()"> <p class="row col-md-10">{{'security.config.ldap.explain'|translate}}</p> - <div class="form-group row col-md-10" *ngFor="let attName of ['host_name','port','base_dn','groups_base_dn','bind_dn','bind_password']"> + <div class="form-group row col-md-10" *ngFor="let attName of ['host_name','port','base_dn','groups_base_dn','bind_dn','bind_password','context_factory']"> <label class="col-md-3 col-form-label" for="{{attName}}">{{'security.config.ldap.attributes.'+attName |translate}}</label> <div [attr.class]="attName=='port'?'col-md-3':'col-md-7'"> <input [attr.type]="attName=='bind_password'?'password':'text'" formControlName="{{attName}}" id="{{attName}}" @@ -37,7 +37,7 @@ <div class="form-group row col-md-10"> <div class="col-md-3">{{'security.config.ldap.flags'|translate}}</div> <div class="col-md-7"> - <div class="form-check" *ngFor="let flagName of ['writable','ssl_enabled','bind_authenticator_enabled','use_role_name_as_group']"> + <div class="form-check pt-1 pb-1" *ngFor="let flagName of ['writable','ssl_enabled','bind_authenticator_enabled','use_role_name_as_group']"> <input class="form-check-input" type="checkbox" formControlName="{{flagName}}" id="{{flagName}}" > <label class="form-check-label " for="{{flagName}}"> @@ -47,4 +47,13 @@ </div> </div> + <div class="row col-md-10 mt-4" > + <button class="btn btn-primary col-md-2" type="submit" + [disabled]="userForm.invalid || !userForm.dirty">{{'form.button.save'|translate}}</button> + <button class="btn btn-primary col-md-2 offset-1" type="button" (click)="checkLdapConnection()" + [disabled]="userForm.invalid || !userForm.dirty">{{'form.button.check'|translate}}</button> + </div> + + </form> + diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.spec.ts index 85bcf6b6a..d29e5e7f6 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.spec.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.spec.ts @@ -16,18 +16,32 @@ * under the License. */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; -import { LdapSecurityComponent, dnValidator } from './ldap-security.component'; -import {ValidatorFn} from "@angular/forms"; +import {LdapSecurityComponent} from './ldap-security.component'; +import {FormBuilder} from "@angular/forms"; +import {RouterTestingModule} from '@angular/router/testing'; +import {NO_ERRORS_SCHEMA} from "@angular/core"; +import {ActivatedRoute, Router} from "@angular/router"; +import {HttpClientTestingModule} from "@angular/common/http/testing"; +import {TranslateModule} from "@ngx-translate/core"; describe('LdapSecurityComponent', () => { let component: LdapSecurityComponent; let fixture: ComponentFixture<LdapSecurityComponent>; + let router; + let route; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ LdapSecurityComponent ] + declarations: [ LdapSecurityComponent ], + providers: [FormBuilder], + schemas:[NO_ERRORS_SCHEMA], + imports:[ + TranslateModule.forRoot(), + RouterTestingModule.withRoutes([]), + HttpClientTestingModule + ] }) .compileComponents(); }); @@ -36,6 +50,8 @@ describe('LdapSecurityComponent', () => { fixture = TestBed.createComponent(LdapSecurityComponent); component = fixture.componentInstance; fixture.detectChanges(); + router = TestBed.get(Router); + route = TestBed.get(ActivatedRoute) }); it('should create', () => { @@ -43,15 +59,30 @@ describe('LdapSecurityComponent', () => { }); describe('Test Custom DN Validator', () => { - it('check valid 1', () => { + it('valid 1', () => { const ctrl = component.userForm.controls['base_dn'] ctrl.setValue('cn=abc'); expect(ctrl.valid).toBeTruthy(); }) - it('check invalid 1', () => { + it('valid 2', () => { + const ctrl = component.userForm.controls['base_dn'] + ctrl.setValue('cn=abc,dc=abc'); + expect(ctrl.valid).toBeTruthy() + }) + it('valid with space', () => { + const ctrl = component.userForm.controls['base_dn'] + ctrl.setValue('cn=abc , dc=abc'); + expect(ctrl.valid).toBeTruthy() + }) + it('invalid postfix', () => { const ctrl = component.userForm.controls['base_dn'] ctrl.setValue('cn=abc,'); expect(ctrl.invalid).toBeTruthy() }) + it('invalid RDN', () => { + const ctrl = component.userForm.controls['base_dn'] + ctrl.setValue('cn=abc,dc,dc=abc'); + expect(ctrl.invalid).toBeTruthy() + }) }); }); diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.ts index 7cc829eeb..bc00ad873 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.ts @@ -16,14 +16,14 @@ * under the License. */ -import { Component, OnInit } from '@angular/core'; +import {Component, OnInit} from '@angular/core'; import {EditBaseComponent} from "@app/modules/shared/edit-base.component"; import {LdapConfiguration} from "@app/model/ldap-configuration"; import {ActivatedRoute} from "@angular/router"; import {AbstractControl, FormBuilder, ValidatorFn, Validators} from "@angular/forms"; import {SecurityService} from "@app/services/security.service"; import {ToastService} from "@app/services/toast.service"; -import {propertyDescriptorPatch} from "zone.js/lib/browser/property-descriptor"; +import {ErrorResult} from "@app/model/error-result"; @Component({ selector: 'app-ldap-security', @@ -33,6 +33,9 @@ import {propertyDescriptorPatch} from "zone.js/lib/browser/property-descriptor"; export class LdapSecurityComponent extends EditBaseComponent<LdapConfiguration> implements OnInit { authenticationMethods=['none','simple','strong'] + formFields = ['host_name', 'port', 'ssl_enabled', 'context_factory', + 'base_dn', 'groups_base_dn', 'bind_dn', 'bind_password', 'authentication_method', 'bind_authenticator_enabled', + 'use_role_name_as_group', 'writable']; constructor(private route: ActivatedRoute, public fb: FormBuilder, private securityService: SecurityService, private toastService: ToastService) { @@ -41,9 +44,10 @@ export class LdapSecurityComponent extends EditBaseComponent<LdapConfiguration> host_name:[''], port:['', [Validators.min(1), Validators.max(65535)]], ssl_enabled:[false], + context_factory:[''], base_dn:['',[dnValidator()]], groups_base_dn:['',[dnValidator()]], - bind_dn:['',[dnValidator()]], + bind_dn:[''], bind_password:[''], authentication_method:['none'], bind_authenticator_enabled:[false], @@ -53,6 +57,23 @@ export class LdapSecurityComponent extends EditBaseComponent<LdapConfiguration> } ngOnInit(): void { + this.securityService.getLdapConfiguration().subscribe( ldapConfiguration => { + this.copyToForm(this.formFields, ldapConfiguration); + if ((ldapConfiguration.context_factory==null || ldapConfiguration.context_factory=='') && ldapConfiguration.available_context_factories.length==1) { + this.userForm.controls['context_factory'].setValue(ldapConfiguration.available_context_factories[0]); + } + if (ldapConfiguration.authentication_method=='') { + this.userForm.controls['authentication_method'].setValue('none'); + } + } + ) + this.userForm.controls['bind_dn'].valueChanges.subscribe(selectedValue => { + if (selectedValue!='' && this.userForm.controls['authentication_method'].value=='none') { + this.userForm.controls['authentication_method'].setValue('simple',{emitEvent: false}) + } else if (selectedValue=='' && this.userForm.controls['authentication_method'].value!='none') { + this.userForm.controls['authentication_method'].setValue('none',{emitEvent: false}) + } + }) } createEntity(): LdapConfiguration { @@ -60,6 +81,11 @@ export class LdapSecurityComponent extends EditBaseComponent<LdapConfiguration> } onSubmit() { + console.log("Saving configuration"); + let config = this.copyFromForm(this.formFields) + + + } getInputClasses(field: string) : string[] { @@ -68,15 +94,32 @@ export class LdapSecurityComponent extends EditBaseComponent<LdapConfiguration> csClasses = []; } csClasses.push('form-control'); - console.log("Classes "+field+" " + csClasses); return csClasses; } + + checkLdapConnection() { + console.log("Checking LDAP connection"); + let config = this.copyFromForm(this.formFields) + this.securityService.verifyLdapConfiguration(config).subscribe(()=>{ + this.toastService.showSuccessByKey('ldap-security', 'security.config.ldap.check_success'); + }, + (error:ErrorResult) =>{ + this.toastService.showErrorByKey('ldap-security', error.firstMessageString()); + } + ); + } } +/** + * This validator checks the DN names for valid RDN segments + */ export function dnValidator(): ValidatorFn { return (control: AbstractControl): {[key: string]: any} | null => { let parts = [] let value = control.value.toString() + if (value=='') { + return null; + } let escape = false; let partKey : string = '' let partValue : string = '' @@ -113,6 +156,9 @@ export function dnValidator(): ValidatorFn { } } + if (partKey=='' || partValue=='') { + return {'invalidDnBadRdn':{value:value,index:value.length-1}} + } return null; }; } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/security.service.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/security.service.ts index 954d44842..8758901b9 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/security.service.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/security.service.ts @@ -23,6 +23,7 @@ import {Observable, throwError} from "rxjs"; import {catchError} from "rxjs/operators"; import {HttpErrorResponse, HttpResponse} from "@angular/common/http"; import {BeanInformation} from "@app/model/bean-information"; +import {LdapConfiguration} from "@app/model/ldap-configuration"; @Injectable({ providedIn: 'root' @@ -66,4 +67,21 @@ export class SecurityService { ); } + getLdapConfiguration() : Observable<LdapConfiguration> { + return this.rest.executeRestCall<LdapConfiguration>("get", "archiva", "security/config/ldap", null).pipe( + catchError((error: HttpErrorResponse) => { + return throwError(this.rest.getTranslatedErrorResult(error)); + }) + ); + } + + verifyLdapConfiguration(ldapConfig : LdapConfiguration) : Observable<HttpResponse<any>> { + return this.rest.executeResponseCall<any>("post", "archiva", "security/config/ldap/verify", ldapConfig).pipe( + catchError((error: HttpErrorResponse) => { + return throwError(this.rest.getTranslatedErrorResult(error)); + }) + ); + } + + } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json index 5bffc1412..4f0b01996 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json @@ -63,7 +63,14 @@ "user.password.violation.numeric": "You must provide a password containing at least {arg0} numeric {arg0, plural, one {character} other {characters}}.", "user.password.violation.reuse": "The password must not match any of the previous {arg0} {arg0, plural, one {password} other {passwords}}.", "user.password.violation.alphanum.only": "You must provide a password containing all alpha-numeric characters.", - "user.password.violation.whitespace.detected": "You must provide a password without whitespace characters." + "user.password.violation.whitespace.detected": "You must provide a password without whitespace characters.", + "archiva.ldap.communication_error": "Communication to LDAP server failed: {arg0}", + "archiva.ldap.invalid_name": "There was a invalid name: {arg0}", + "archiva.ldap.generic_error": "LDAP Error: {arg0}", + "archiva.ldap.service_unavailable": "LDAP Server not available: {arg0}", + "archiva.ldap.authentication.failed": "LDAP Authentication failed: {arg0}", + "archiva.ldap.authentication.not_supported": "LDAP Authentication not supported: {arg0}", + "archiva.ldap.no_permissions": "No permission on LDAP server: {arg0}" }, "users": { "attributes": { @@ -206,13 +213,14 @@ "port": "Port", "base_dn": "Base DN", "groups_base_dn": "Base DN for Group Search", - "bind_dn": "Bind User DN", + "bind_dn": "Bind User", "bind_password":"Bind Password", "authentication_method": "Method used for Bind Authentication", - "bind_authenticator_enabled": "Use LDAP Bind during archiva authentication", + "bind_authenticator_enabled": "Use LDAP Bind for Archiva authentication", "use_role_name_as_group": "Archiva role names are LDAP group names", "writable": "Bind User can write to LDAP Server", - "ssl_enabled": "Enable SSL" + "ssl_enabled": "Enable SSL", + "context_factory": "Context Factory" }, "flags": "Flags" @@ -242,7 +250,8 @@ "button": { "yes": "Yes", "no": "No", - "save": "Save Changes" + "save": "Save Changes", + "check": "Check configuration" }, "edit": "Edit", "emptyContent": "No values", |