1 package org.apache.archiva.rest.services.v2;/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 import org.apache.archiva.admin.model.RepositoryAdminException;
20 import org.apache.archiva.admin.model.beans.RedbackRuntimeConfiguration;
21 import org.apache.archiva.admin.model.runtime.RedbackRuntimeConfigurationAdmin;
22 import org.apache.archiva.components.cache.Cache;
23 import org.apache.archiva.components.rest.model.PagedResult;
24 import org.apache.archiva.components.rest.model.PropertyEntry;
25 import org.apache.archiva.components.rest.util.PagingHelper;
26 import org.apache.archiva.components.rest.util.QueryHelper;
27 import org.apache.archiva.redback.authentication.Authenticator;
28 import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory;
29 import org.apache.archiva.redback.common.ldap.user.LdapUserMapper;
30 import org.apache.archiva.redback.policy.CookieSettings;
31 import org.apache.archiva.redback.policy.PasswordRule;
32 import org.apache.archiva.redback.rbac.RBACManager;
33 import org.apache.archiva.redback.role.RoleManager;
34 import org.apache.archiva.redback.users.UserManager;
35 import org.apache.archiva.rest.api.model.UserManagerImplementationInformation;
36 import org.apache.archiva.rest.api.model.v2.BeanInformation;
37 import org.apache.archiva.rest.api.model.v2.CacheConfiguration;
38 import org.apache.archiva.rest.api.model.v2.LdapConfiguration;
39 import org.apache.archiva.rest.api.model.v2.SecurityConfiguration;
40 import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException;
41 import org.apache.archiva.rest.api.services.v2.ErrorMessage;
42 import org.apache.archiva.rest.api.services.v2.SecurityConfigurationService;
43 import org.apache.commons.collections4.CollectionUtils;
44 import org.apache.commons.collections4.ListUtils;
45 import org.apache.commons.lang3.StringUtils;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.context.ApplicationContext;
49 import org.springframework.stereotype.Service;
51 import javax.annotation.PostConstruct;
52 import javax.inject.Inject;
53 import javax.inject.Named;
54 import javax.management.Query;
55 import javax.ws.rs.core.Response;
56 import java.util.ArrayList;
57 import java.util.Collection;
58 import java.util.Collections;
59 import java.util.Comparator;
60 import java.util.List;
62 import java.util.Objects;
63 import java.util.ResourceBundle;
64 import java.util.function.Predicate;
65 import java.util.stream.Collectors;
67 import static org.apache.archiva.rest.services.v2.ErrorKeys.REPOSITORY_ADMIN_ERROR;
70 * @author Martin Stockhammer <martin_s@apache.org>
72 @Service( "v2.defaultSecurityConfigurationService" )
73 public class DefaultSecurityConfigurationService implements SecurityConfigurationService
75 private static final Logger log = LoggerFactory.getLogger( DefaultSecurityConfigurationService.class );
77 private static final QueryHelper<PropertyEntry> PROP_QUERY_HELPER = new QueryHelper( new String[]{"key"} );
78 private static final PagingHelper PROP_PAGING_HELPER = new PagingHelper( );
80 PROP_QUERY_HELPER.addStringFilter( "key", PropertyEntry::getKey );
81 PROP_QUERY_HELPER.addStringFilter( "value", PropertyEntry::getValue );
82 PROP_QUERY_HELPER.addNullsafeFieldComparator( "key", PropertyEntry::getKey );
83 PROP_QUERY_HELPER.addNullsafeFieldComparator( "value", PropertyEntry::getValue );
87 private ResourceBundle bundle;
91 private RedbackRuntimeConfigurationAdmin redbackRuntimeConfigurationAdmin;
94 private ApplicationContext applicationContext;
97 @Named(value = "userManager#default")
98 private UserManager userManager;
101 @Named(value = "rbacManager#default")
102 private RBACManager rbacManager;
105 private RoleManager roleManager;
108 @Named(value = "ldapConnectionFactory#configurable")
109 private LdapConnectionFactory ldapConnectionFactory;
112 private LdapUserMapper ldapUserMapper;
115 @Named(value = "cache#users")
116 private Cache usersCache;
121 bundle = ResourceBundle.getBundle( "org.apache.archiva.rest.RestBundle" );
125 public SecurityConfiguration getConfiguration( ) throws ArchivaRestServiceException
129 RedbackRuntimeConfiguration redbackRuntimeConfiguration =
130 redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
132 log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
134 return SecurityConfiguration.ofRedbackConfiguration( redbackRuntimeConfiguration );
136 catch ( RepositoryAdminException e )
138 throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) );
141 private void updateConfig(SecurityConfiguration newConfig, RedbackRuntimeConfiguration rbConfig) {
142 rbConfig.setUserManagerImpls( newConfig.getActiveUserManagers() );
143 rbConfig.setRbacManagerImpls( newConfig.getActiveRbacManagers() );
144 rbConfig.setUseUsersCache( newConfig.isUserCacheEnabled() );
145 Map<String, String> props = rbConfig.getConfigurationProperties( );
146 for ( Map.Entry<String,String> newProp : newConfig.getProperties().entrySet() ) {
147 props.put( newProp.getKey( ), newProp.getValue( ) );
151 private void updateConfig(LdapConfiguration newConfig, RedbackRuntimeConfiguration rbConfig) {
152 org.apache.archiva.admin.model.beans.LdapConfiguration ldapConfig = rbConfig.getLdapConfiguration( );
153 ldapConfig.setBaseDn( newConfig.getBaseDn( ) );
154 ldapConfig.setAuthenticationMethod( newConfig.getAuthenticationMethod() );
155 ldapConfig.setBindAuthenticatorEnabled( newConfig.isBindAuthenticatorEnabled( ) );
156 ldapConfig.setBindDn( newConfig.getBindDn() );
157 ldapConfig.setSsl( newConfig.isSslEnabled( ) );
158 ldapConfig.setBaseGroupsDn( newConfig.getGroupsBaseDn() );
159 ldapConfig.setHostName( newConfig.getHostName() );
160 ldapConfig.setPort( newConfig.getPort() );
161 ldapConfig.setPassword( newConfig.getBindPassword() );
162 ldapConfig.setUseRoleNameAsGroup( newConfig.isUseRoleNameAsGroup() );
163 ldapConfig.setWritable( newConfig.isWritable( ) );
165 Map<String, String> props = ldapConfig.getExtraProperties( );
166 for ( Map.Entry<String,String> newProp : newConfig.getProperties().entrySet() ) {
167 props.put( newProp.getKey( ), newProp.getValue( ) );
171 private void updateConfig(CacheConfiguration newConfig, RedbackRuntimeConfiguration rbConfig) {
172 org.apache.archiva.admin.model.beans.CacheConfiguration cacheConfig = rbConfig.getUsersCacheConfiguration( );
173 cacheConfig.setMaxElementsInMemory( newConfig.getMaxEntriesInMemory());
174 cacheConfig.setMaxElementsOnDisk( newConfig.getMaxEntriesOnDisk() );
175 cacheConfig.setTimeToLiveSeconds( newConfig.getTimeToLiveSeconds() );
176 cacheConfig.setTimeToIdleSeconds( newConfig.getTimeToIdleSeconds() );
180 public Response updateConfiguration( SecurityConfiguration newConfiguration ) throws ArchivaRestServiceException
184 RedbackRuntimeConfiguration conf = redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
185 boolean userManagerChanged = !CollectionUtils.isEqualCollection( newConfiguration.getActiveUserManagers( ), conf.getUserManagerImpls() );
186 boolean rbacManagerChanged = !CollectionUtils.isEqualCollection( newConfiguration.getActiveRbacManagers( ), conf.getRbacManagerImpls( ) );
188 boolean ldapConfigured = false;
189 for (String um : newConfiguration.getActiveUserManagers()) {
190 if (um.contains("ldap")) {
194 if (!ldapConfigured) {
195 for (String rbm : newConfiguration.getActiveRbacManagers()) {
196 if (rbm.contains("ldap")) {
197 ldapConfigured = true;
202 updateConfig( newConfiguration, conf);
203 redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( conf );
205 if ( userManagerChanged )
207 log.info( "user managerImpls changed to {} so reload it",
208 newConfiguration.getActiveUserManagers() );
209 userManager.initialize();
212 if ( rbacManagerChanged )
214 log.info( "rbac manager changed to {} so reload it",
215 newConfiguration.getActiveRbacManagers() );
216 rbacManager.initialize();
217 roleManager.initialize();
220 if (ldapConfigured) {
222 ldapConnectionFactory.initialize();
223 } catch (Exception e) {
224 log.error( "Could not initialize LDAP connection factory: {}", e.getMessage( ) );
225 throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_CF_INIT_FAILED, e.getMessage() ) );
228 Collection<PasswordRule> passwordRules = applicationContext.getBeansOfType( PasswordRule.class ).values();
230 for ( PasswordRule passwordRule : passwordRules )
232 passwordRule.initialize();
235 Collection<CookieSettings> cookieSettingsList =
236 applicationContext.getBeansOfType( CookieSettings.class ).values();
238 for ( CookieSettings cookieSettings : cookieSettingsList )
240 cookieSettings.initialize();
243 Collection<Authenticator> authenticators =
244 applicationContext.getBeansOfType( Authenticator.class ).values();
246 for ( Authenticator authenticator : authenticators )
249 log.debug("Initializing authenticatior "+authenticator.getId());
250 authenticator.initialize();
251 } catch (Exception e) {
252 log.error("Initialization of authenticator failed "+authenticator.getId(),e);
256 if (ldapConfigured) {
258 ldapUserMapper.initialize();
259 } catch (Exception e) {
260 throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.LDAP_USER_MAPPER_INIT_FAILED, e.getMessage( ) ) );
264 catch ( RepositoryAdminException e )
266 throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
268 return Response.ok( ).build();
272 public PagedResult<PropertyEntry> getConfigurationProperties( String searchTerm, Integer offset, Integer limit, List<String> orderBy, String order ) throws ArchivaRestServiceException
276 RedbackRuntimeConfiguration redbackRuntimeConfiguration =
277 redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
279 log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
281 boolean ascending = PROP_QUERY_HELPER.isAscending( order );
282 Predicate<PropertyEntry> filter = PROP_QUERY_HELPER.getQueryFilter( searchTerm );
283 Comparator<PropertyEntry> comparator = PROP_QUERY_HELPER.getComparator( orderBy, ascending );
284 Map<String, String> props = redbackRuntimeConfiguration.getConfigurationProperties( );
285 int totalCount = props.size( );
286 List<PropertyEntry> result = props.entrySet( ).stream( ).map(
287 entry -> new PropertyEntry( entry.getKey( ), entry.getValue( ) )
289 .sorted( comparator )
290 .skip( offset ).limit( limit )
291 .collect( Collectors.toList( ) );
292 return new PagedResult<>( totalCount, offset, limit, result );
294 catch ( RepositoryAdminException e )
296 throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) );
301 public PropertyEntry getConfigurationProperty( String propertyName ) throws ArchivaRestServiceException
305 RedbackRuntimeConfiguration conf = redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
306 if (conf.getConfigurationProperties().containsKey( propertyName )) {
307 String value = conf.getConfigurationProperties( ).get( propertyName );
308 return new PropertyEntry( propertyName, value );
310 throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.PROPERTY_NOT_FOUND ), 404 );
314 catch ( RepositoryAdminException e )
316 throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
322 public Response updateConfigurationProperty( String propertyName, PropertyEntry propertyValue ) throws ArchivaRestServiceException
326 RedbackRuntimeConfiguration conf = redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
327 if (conf.getConfigurationProperties().containsKey( propertyName )) {
328 conf.getConfigurationProperties( ).put( propertyName, propertyValue.getValue( ) );
329 redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( conf );
330 return Response.ok( ).build( );
332 throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.PROPERTY_NOT_FOUND ), 404 );
336 catch ( RepositoryAdminException e )
338 throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
343 public LdapConfiguration getLdapConfiguration( ) throws ArchivaRestServiceException
347 RedbackRuntimeConfiguration redbackRuntimeConfiguration =
348 redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
350 log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
352 return LdapConfiguration.of( redbackRuntimeConfiguration.getLdapConfiguration() );
354 catch ( RepositoryAdminException e )
356 throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) );
362 public Response updateLdapConfiguration( LdapConfiguration configuration ) throws ArchivaRestServiceException
366 RedbackRuntimeConfiguration redbackRuntimeConfiguration =
367 redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
369 log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
371 updateConfig( configuration, redbackRuntimeConfiguration );
373 redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( redbackRuntimeConfiguration );
375 return Response.ok( ).build( );
378 catch ( RepositoryAdminException e )
380 throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) );
385 public CacheConfiguration getCacheConfiguration( ) throws ArchivaRestServiceException
389 RedbackRuntimeConfiguration redbackRuntimeConfiguration =
390 redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
392 log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
394 return CacheConfiguration.of( redbackRuntimeConfiguration.getUsersCacheConfiguration() );
396 catch ( RepositoryAdminException e )
398 throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) );
404 public Response updateCacheConfiguration( CacheConfiguration cacheConfiguration ) throws ArchivaRestServiceException
408 RedbackRuntimeConfiguration redbackRuntimeConfiguration =
409 redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
411 log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
412 updateConfig( cacheConfiguration, redbackRuntimeConfiguration );
413 redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( redbackRuntimeConfiguration );
414 return Response.ok( ).build( );
416 catch ( RepositoryAdminException e )
418 throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) );
423 public List<BeanInformation> getAvailableUserManagers( ) throws ArchivaRestServiceException
425 Map<String, UserManager> beans = applicationContext.getBeansOfType( UserManager.class );
427 if ( beans.isEmpty() )
429 return Collections.emptyList();
432 return beans.entrySet( ).stream( )
433 .filter( entry -> entry.getValue().isFinalImplementation() )
434 .map( (Map.Entry<String, UserManager> entry) -> {
435 UserManager um = entry.getValue( );
436 String id = StringUtils.substringAfter( entry.getKey( ), "#" );
437 String displayName = bundle.getString( "user_manager." + id + ".display_name" );
438 String description = bundle.getString( "user_manager." + id + ".description" );
439 return new BeanInformation( StringUtils.substringAfter( entry.getKey( ), "#" ), displayName, um.getDescriptionKey( ), description, um.isReadOnly( ) );
440 } ).collect( Collectors.toList());
444 public List<BeanInformation> getAvailableRbacManagers( ) throws ArchivaRestServiceException
446 Map<String, RBACManager> beans = applicationContext.getBeansOfType( RBACManager.class );
448 if ( beans.isEmpty() )
450 return Collections.emptyList();
453 return beans.entrySet( ).stream( )
454 .filter( entry -> entry.getValue().isFinalImplementation() )
455 .map( (Map.Entry<String, RBACManager> entry) -> {
456 RBACManager rm = entry.getValue( );
457 String id = StringUtils.substringAfter( entry.getKey( ), "#" );
458 String displayName = bundle.getString( "rbac_manager." + id + ".display_name" );
459 String description = bundle.getString( "rbac_manager." + id + ".description" );
460 return new BeanInformation( StringUtils.substringAfter( entry.getKey( ), "#" ), displayName, rm.getDescriptionKey( ), description, rm.isReadOnly( ) );
461 } ).collect( Collectors.toList());