String defaultDescription;
boolean readonly;
+ public BeanInformation( )
+ {
+ }
+
+ public BeanInformation( String id, String displayName, String descriptionKey, String defaultDescription, boolean readonly )
+ {
+ this.id = id;
+ this.displayName = displayName;
+ this.descriptionKey = descriptionKey;
+ this.defaultDescription = defaultDescription;
+ this.readonly = readonly;
+ }
+
@Schema(description = "The identifier")
public String getId( )
{
// no op
}
- public CacheConfiguration of( org.apache.archiva.admin.model.beans.CacheConfiguration beanConfiguration ) {
+ public static CacheConfiguration of( org.apache.archiva.admin.model.beans.CacheConfiguration beanConfiguration ) {
CacheConfiguration newConfig = new CacheConfiguration( );
newConfig.setMaxEntriesInMemory( beanConfiguration.getMaxElementsInMemory() );
newConfig.setMaxEntriesOnDisk( beanConfiguration.getMaxElementsOnDisk() );
SecurityConfiguration getConfiguration()
throws ArchivaRestServiceException;
+ @Path( "config/properties" )
@GET
@Produces( { APPLICATION_JSON } )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@Parameter(name = "q", description = "Search term"),
@Parameter(name = "offset", description = "The offset of the first element returned"),
@Parameter(name = "limit", description = "Maximum number of items to return in the response"),
- @Parameter(name = "orderBy", description = "List of attribute used for sorting (user_id, fullName, email, created"),
+ @Parameter(name = "orderBy", description = "List of attribute used for sorting (key, value)"),
@Parameter(name = "order", description = "The sort order. Either ascending (asc) or descending (desc)")
},
security = {
PagedResult<PropertyEntry> getConfigurationProperties( @QueryParam("q") @DefaultValue( "" ) String searchTerm,
@QueryParam( "offset" ) @DefaultValue( "0" ) Integer offset,
@QueryParam( "limit" ) @DefaultValue( value = DEFAULT_PAGE_LIMIT ) Integer limit,
- @QueryParam( "orderBy") @DefaultValue( "id" ) List<String> orderBy,
+ @QueryParam( "orderBy") @DefaultValue( "key" ) List<String> orderBy,
@QueryParam("order") @DefaultValue( "asc" ) String order ) throws ArchivaRestServiceException;
- @Path("ldap")
+ @Path("config/ldap")
@GET
@Produces({ MediaType.APPLICATION_JSON })
@RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION)
LdapConfiguration getLdapConfiguration( ) throws ArchivaRestServiceException;
- @Path("user/cache")
+ @Path("config/cache")
@GET
@Produces({ MediaType.APPLICATION_JSON })
@RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION)
)
CacheConfiguration getCacheConfiguration( ) throws ArchivaRestServiceException;
- @Path("user/managers")
+ @Path("user_managers")
@GET
@Produces({ MediaType.APPLICATION_JSON })
@RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION)
List<BeanInformation> getAvailableUserManagers()
throws ArchivaRestServiceException;
- @Path("rbac/managers")
+ @Path("rbac_managers")
@GET
@Produces({ MediaType.APPLICATION_JSON })
@RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION)
<artifactId>jakarta.transaction-api</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.archiva.redback</groupId>
+ <artifactId>redback-rbac-ldap</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.archiva.redback</groupId>
<artifactId>redback-rbac-jpa</artifactId>
- <version>${redback.version}</version>
<scope>test</scope>
</dependency>
<dependency>
import org.apache.archiva.admin.model.runtime.RedbackRuntimeConfigurationAdmin;
import org.apache.archiva.components.rest.model.PagedResult;
import org.apache.archiva.components.rest.model.PropertyEntry;
+import org.apache.archiva.components.rest.util.PagingHelper;
+import org.apache.archiva.components.rest.util.QueryHelper;
+import org.apache.archiva.redback.rbac.RBACManager;
+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;
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.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
+import javax.annotation.PostConstruct;
import javax.inject.Inject;
+import javax.management.Query;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ResourceBundle;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
import static org.apache.archiva.rest.services.v2.ErrorKeys.REPOSITORY_ADMIN_ERROR;
/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
-@Service("v2.defaultSecurityConfigurationService")
+@Service( "v2.defaultSecurityConfigurationService" )
public class DefaultSecurityConfigurationService implements SecurityConfigurationService
{
private static final Logger log = LoggerFactory.getLogger( DefaultSecurityConfigurationService.class );
+ private static final QueryHelper<PropertyEntry> PROP_QUERY_HELPER = new QueryHelper( new String[]{"key"} );
+ private static final PagingHelper PROP_PAGING_HELPER = new PagingHelper( );
+ static {
+ PROP_QUERY_HELPER.addStringFilter( "key", PropertyEntry::getKey );
+ PROP_QUERY_HELPER.addStringFilter( "value", PropertyEntry::getValue );
+ PROP_QUERY_HELPER.addNullsafeFieldComparator( "key", PropertyEntry::getKey );
+ PROP_QUERY_HELPER.addNullsafeFieldComparator( "value", PropertyEntry::getValue );
+
+ }
+
+ private ResourceBundle bundle;
+
+
@Inject
private RedbackRuntimeConfigurationAdmin redbackRuntimeConfigurationAdmin;
+ @Inject
+ private ApplicationContext applicationContext;
+
+ @PostConstruct
+ void init() {
+ bundle = ResourceBundle.getBundle( "org.apache.archiva.rest.RestBundle" );
+ }
+
@Override
public SecurityConfiguration getConfiguration( ) throws ArchivaRestServiceException
{
try
{
RedbackRuntimeConfiguration redbackRuntimeConfiguration =
- redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration();
+ redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
@Override
public PagedResult<PropertyEntry> getConfigurationProperties( String searchTerm, Integer offset, Integer limit, List<String> orderBy, String order ) throws ArchivaRestServiceException
{
- return null;
+ try
+ {
+ RedbackRuntimeConfiguration redbackRuntimeConfiguration =
+ redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
+
+ log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
+
+ boolean ascending = PROP_QUERY_HELPER.isAscending( order );
+ Predicate<PropertyEntry> filter = PROP_QUERY_HELPER.getQueryFilter( searchTerm );
+ Comparator<PropertyEntry> comparator = PROP_QUERY_HELPER.getComparator( orderBy, ascending );
+ Map<String, String> props = redbackRuntimeConfiguration.getConfigurationProperties( );
+ int totalCount = props.size( );
+ List<PropertyEntry> result = props.entrySet( ).stream( ).map(
+ entry -> new PropertyEntry( entry.getKey( ), entry.getValue( ) )
+ ).filter( filter )
+ .sorted( comparator )
+ .skip( offset ).limit( limit )
+ .collect( Collectors.toList( ) );
+ return new PagedResult<>( totalCount, offset, limit, result );
+ }
+ catch ( RepositoryAdminException e )
+ {
+ throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) );
+ }
}
@Override
public LdapConfiguration getLdapConfiguration( ) throws ArchivaRestServiceException
{
- return null;
+ try
+ {
+ RedbackRuntimeConfiguration redbackRuntimeConfiguration =
+ redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
+
+ log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
+
+ return LdapConfiguration.of( redbackRuntimeConfiguration.getLdapConfiguration() );
+ }
+ catch ( RepositoryAdminException e )
+ {
+ throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) );
+ }
+
}
@Override
public CacheConfiguration getCacheConfiguration( ) throws ArchivaRestServiceException
{
- return null;
+ try
+ {
+ RedbackRuntimeConfiguration redbackRuntimeConfiguration =
+ redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( );
+
+ log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
+
+ return CacheConfiguration.of( redbackRuntimeConfiguration.getUsersCacheConfiguration() );
+ }
+ catch ( RepositoryAdminException e )
+ {
+ throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) );
+ }
+
}
@Override
public List<BeanInformation> getAvailableUserManagers( ) throws ArchivaRestServiceException
{
- return null;
+ Map<String, UserManager> beans = applicationContext.getBeansOfType( UserManager.class );
+
+ if ( beans.isEmpty() )
+ {
+ return Collections.emptyList();
+ }
+
+ return beans.entrySet( ).stream( )
+ .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());
}
@Override
public List<BeanInformation> getAvailableRbacManagers( ) throws ArchivaRestServiceException
{
- return null;
+ Map<String, RBACManager> beans = applicationContext.getBeansOfType( RBACManager.class );
+
+ if ( beans.isEmpty() )
+ {
+ return Collections.emptyList();
+ }
+
+ return beans.entrySet( ).stream( )
+ .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());
}
}
--- /dev/null
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+user_manager.ldap.display_name=LDAP User Manager
+user_manager.ldap.description=User Manager that connects to LDAP server.
+user_manager.jpa.display_name=Database User Manager
+user_manager.jpa.description=User Manager that persists the user entries in a database.
+rbac_manager.ldap.display_name=LDAP RBAC Manager
+rbac_manager.ldap.description=RBAC Manager that connects to LDAP server.
+rbac_manager.jpa.display_name=Database RBAC Manager
+rbac_manager.jpa.description=RBAC Manager that persists the role entries in a database.
--- /dev/null
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+user_manager.ldap.display_name=LDAP User Manager
+user_manager.ldap.description=User Manager that connects to LDAP server.
+user_manager.jpa.display_name=Database User Manager
+user_manager.jpa.description=User Manager that persists the user entries in a database.
*/
import io.restassured.response.Response;
+import org.apache.archiva.components.rest.model.PagedResult;
+import org.apache.archiva.components.rest.model.PropertyEntry;
+import org.apache.archiva.rest.api.model.v2.BeanInformation;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
+import java.util.List;
+
import static io.restassured.RestAssured.given;
import static io.restassured.http.ContentType.JSON;
import static org.junit.jupiter.api.Assertions.*;
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.get( "config" )
- .prettyPeek()
.then( ).statusCode( 200 ).extract( ).response( );
assertNotNull( response );
assertEquals( "jpa", response.getBody( ).jsonPath( ).getString( "active_user_managers[0]" ) );
assertFalse( response.getBody( ).jsonPath( ).getBoolean( "ldap_active" ) );
}
+ @Test
+ void testGetConfigurationProperties() {
+ String token = getAdminToken( );
+ Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
+ .when( )
+ .get( "config/properties" )
+ .then( ).statusCode( 200 ).extract( ).response( );
+ assertNotNull( response );
+ PagedResult<PropertyEntry> result = response.getBody( ).jsonPath( ).getObject( "", PagedResult.class );
+ List<PropertyEntry> propList = response.getBody( ).jsonPath( ).getList( "data", PropertyEntry.class );
+ assertEquals( 10, result.getPagination( ).getLimit( ) );
+ assertEquals( 0, result.getPagination( ).getOffset( ) );
+ assertEquals( 47, result.getPagination( ).getTotalCount( ) );
+ assertEquals( "authentication.jwt.keystoreType", propList.get( 0 ).getKey() );
+
+ response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
+ .when( )
+ .queryParam( "offset", "3" )
+ .queryParam( "limit", "5" )
+ .get( "config/properties" )
+ .then( ).statusCode( 200 ).extract( ).response( );
+
+ assertNotNull( response );
+ result = response.getBody( ).jsonPath( ).getObject( "", PagedResult.class );
+ assertEquals( 5, result.getPagination( ).getLimit( ) );
+ assertEquals( 47, result.getPagination( ).getTotalCount( ) );
+ propList = response.getBody( ).jsonPath( ).getList( "data", PropertyEntry.class );
+ assertEquals( "authentication.jwt.refreshLifetimeMs", propList.get( 0 ).getKey() );
+ }
+
+ @Test
+ void testGetLdapConfiguration() {
+ String token = getAdminToken( );
+ Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
+ .when( )
+ .get( "config/ldap" )
+ .then( ).statusCode( 200 ).extract( ).response( );
+ assertNotNull( response );
+ assertEquals( "", response.getBody( ).jsonPath( ).get( "host_name" ) );
+ assertEquals( 13, response.getBody( ).jsonPath( ).getMap( "properties" ).size( ) );
+ }
+
+ @Test
+ void testGetCacheConfiguration() {
+ String token = getAdminToken( );
+ Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
+ .when( )
+ .get( "config/cache" )
+ .then( ).statusCode( 200 ).extract( ).response( );
+ assertNotNull( response );
+ }
+
+ @Test
+ void testGetUserManagers() {
+ String token = getAdminToken( );
+ Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
+ .when( )
+ .get( "user_managers" )
+ .prettyPeek()
+ .then( ).statusCode( 200 ).extract( ).response( );
+ assertNotNull( response );
+ List<BeanInformation> usrList = response.getBody( ).jsonPath( ).getList( "", BeanInformation.class );
+ assertEquals( 2, usrList.size( ) );
+ assertTrue( usrList.stream( ).anyMatch( bi -> "LDAP User Manager".equals( bi.getDisplayName( ) ) ) );
+ assertTrue( usrList.stream( ).anyMatch( bi -> "Database User Manager".equals( bi.getDisplayName( ) ) ) );
+ }
+
+ @Test
+ void testGetRbacManagers() {
+ String token = getAdminToken( );
+ Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
+ .when( )
+ .get( "rbac_managers" )
+ .prettyPeek()
+ .then( ).statusCode( 200 ).extract( ).response( );
+ assertNotNull( response );
+ List<BeanInformation> rbacList = response.getBody( ).jsonPath( ).getList( "", BeanInformation.class );
+ assertEquals( 2, rbacList.size( ) );
+ assertTrue( rbacList.stream( ).anyMatch( bi -> "Database RBAC Manager".equals( bi.getDisplayName( ) ) ) );
+ assertTrue( rbacList.stream( ).anyMatch( bi -> "LDAP RBAC Manager".equals( bi.getDisplayName( ) ) ) );
+ }
+
}