<properties>
<enunciate.docsDir>${project.build.outputDirectory}/rest-docs-archiva-rest-api</enunciate.docsDir>
<site.staging.base>${project.parent.parent.parent.basedir}</site.staging.base>
+ <openapi.config.file>${project.basedir}/src/main/resources/archiva/openapi-configuration.yaml</openapi.config.file>
+ <openapi.prefix>archiva</openapi.prefix>
</properties>
<dependencies>
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.apache.archiva.components</groupId>
+ <artifactId>archiva-components-rest-util</artifactId>
+ </dependency>
+
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-jaxrs2</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.xml.bind</groupId>
+ <artifactId>jakarta.xml.bind-api</artifactId>
+ </dependency>
</dependencies>
<build>
--- /dev/null
+package org.apache.archiva.rest.api.model.v2;/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@XmlRootElement(name="beanInformation")
+public class BeanInformation implements Serializable
+{
+ private static final long serialVersionUID = -432385743277355987L;
+ String id;
+ String displayName;
+ String descriptionKey;
+ String defaultDescription;
+ boolean readonly;
+
+ @Schema(description = "The identifier")
+ public String getId( )
+ {
+ return id;
+ }
+
+ public void setId( String id )
+ {
+ this.id = id;
+ }
+
+ @Schema(description = "The display name")
+ public String getDisplayName( )
+ {
+ return displayName;
+ }
+
+ public void setDisplayName( String displayName )
+ {
+ this.displayName = displayName;
+ }
+
+ @Schema(description = "The translation key for the description")
+ public String getDescriptionKey( )
+ {
+ return descriptionKey;
+ }
+
+ public void setDescriptionKey( String descriptionKey )
+ {
+ this.descriptionKey = descriptionKey;
+ }
+
+ @Schema(description = "The description translated in the default language")
+ public String getDefaultDescription( )
+ {
+ return defaultDescription;
+ }
+
+ public void setDefaultDescription( String defaultDescription )
+ {
+ this.defaultDescription = defaultDescription;
+ }
+
+ @Schema(description = "True, if this bean cannot be removed")
+ public boolean isReadonly( )
+ {
+ return readonly;
+ }
+
+ public void setReadonly( boolean readonly )
+ {
+ this.readonly = readonly;
+ }
+}
--- /dev/null
+package org.apache.archiva.rest.api.model.v2;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+/**
+ * @author Olivier Lamy
+ * @author Martin Stockhammer
+ * @since 3.0
+ */
+@XmlRootElement( name = "cacheConfiguration" )
+public class CacheConfiguration
+ implements Serializable
+{
+ private static final long serialVersionUID = 5479989049980673894L;
+ /**
+ * TimeToIdleSeconds.
+ */
+ private int timeToIdleSeconds = -1;
+
+ /**
+ * TimeToLiveSeconds.
+ */
+ private int timeToLiveSeconds = -1;
+
+ /**
+ * max elements in memory.
+ */
+ private int maxEntriesInMemory = -1;
+
+ /**
+ * max elements on disk.
+ */
+ private int maxEntriesOnDisk = -1;
+
+ public CacheConfiguration()
+ {
+ // no op
+ }
+
+ public CacheConfiguration of( org.apache.archiva.admin.model.beans.CacheConfiguration beanConfiguration ) {
+ CacheConfiguration newConfig = new CacheConfiguration( );
+ newConfig.setMaxEntriesInMemory( beanConfiguration.getMaxElementsInMemory() );
+ newConfig.setMaxEntriesOnDisk( beanConfiguration.getMaxElementsOnDisk() );
+ newConfig.setTimeToIdleSeconds( beanConfiguration.getTimeToIdleSeconds( ) );
+ newConfig.setTimeToLiveSeconds( beanConfiguration.getTimeToLiveSeconds( ) );
+ return newConfig;
+ }
+
+ @Schema(description = "The maximum number of seconds an element can exist in the cache without being accessed. "+
+ "The element expires at this limit and will no longer be returned from the cache.")
+ public int getTimeToIdleSeconds()
+ {
+ return timeToIdleSeconds;
+ }
+
+ public void setTimeToIdleSeconds( int timeToIdleSeconds )
+ {
+ this.timeToIdleSeconds = timeToIdleSeconds;
+ }
+
+ @Schema(description = "The maximum number of seconds an element can exist in the cache regardless of use. "+
+ "The element expires at this limit and will no longer be returned from the cache.")
+ public int getTimeToLiveSeconds()
+ {
+ return timeToLiveSeconds;
+ }
+
+ public void setTimeToLiveSeconds( int timeToLiveSeconds )
+ {
+ this.timeToLiveSeconds = timeToLiveSeconds;
+ }
+
+ @Schema(description = "The maximum cache entries to keep in memory. If the limit is reached, older entries will be evicted, or persisted on disk.")
+ public int getMaxEntriesInMemory()
+ {
+ return maxEntriesInMemory;
+ }
+
+ public void setMaxEntriesInMemory( int maxEntriesInMemory )
+ {
+ this.maxEntriesInMemory = maxEntriesInMemory;
+ }
+
+ @Schema(description = "The maximum cache entries to keep on disk. If the limit is reached, older entries will be evicted.")
+ public int getMaxEntriesOnDisk()
+ {
+ return maxEntriesOnDisk;
+ }
+
+ public void setMaxEntriesOnDisk( int maxEntriesOnDisk )
+ {
+ this.maxEntriesOnDisk = maxEntriesOnDisk;
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o ) return true;
+ if ( o == null || getClass( ) != o.getClass( ) ) return false;
+
+ CacheConfiguration that = (CacheConfiguration) o;
+
+ if ( timeToIdleSeconds != that.timeToIdleSeconds ) return false;
+ if ( timeToLiveSeconds != that.timeToLiveSeconds ) return false;
+ if ( maxEntriesInMemory != that.maxEntriesInMemory ) return false;
+ return maxEntriesOnDisk == that.maxEntriesOnDisk;
+ }
+
+ @Override
+ public int hashCode( )
+ {
+ int result = timeToIdleSeconds;
+ result = 31 * result + timeToLiveSeconds;
+ result = 31 * result + maxEntriesInMemory;
+ result = 31 * result + maxEntriesOnDisk;
+ return result;
+ }
+
+ @Override
+ public String toString()
+ {
+ final StringBuilder sb = new StringBuilder();
+ sb.append( "CacheConfiguration" );
+ sb.append( "{timeToIdleSeconds=" ).append( timeToIdleSeconds );
+ sb.append( ", timeToLiveSeconds=" ).append( timeToLiveSeconds );
+ sb.append( ", maxElementsInMemory=" ).append( maxEntriesInMemory );
+ sb.append( ", maxElementsOnDisk=" ).append( maxEntriesOnDisk );
+ sb.append( '}' );
+ return sb.toString();
+ }
+}
--- /dev/null
+package org.apache.archiva.rest.api.model.v2;/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeMap;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@XmlRootElement(name="ldapConfiguration")
+public class LdapConfiguration implements Serializable
+{
+ private static final long serialVersionUID = -4736767846016398583L;
+
+ 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 boolean bindAuthenticatorEnabled = true;
+ private boolean useRoleNameAsGroup = false;
+ private final Map<String, String> properties = new TreeMap<>();
+ private boolean writable = false;
+
+ public LdapConfiguration( )
+ {
+ }
+
+ public static LdapConfiguration of( org.apache.archiva.admin.model.beans.LdapConfiguration ldapConfiguration ) {
+ LdapConfiguration newCfg = new LdapConfiguration( );
+ newCfg.setAuthenticationMethod( ldapConfiguration.getAuthenticationMethod( ) );
+ newCfg.setBaseDn( ldapConfiguration.getBaseDn( ) );
+ newCfg.setGroupsBaseDn( ldapConfiguration.getBaseGroupsDn() );
+ newCfg.setBindDn( ldapConfiguration.getBindDn() );
+ newCfg.setBindPassword( ldapConfiguration.getPassword() );
+ newCfg.setBindAuthenticatorEnabled( ldapConfiguration.isBindAuthenticatorEnabled() );
+ newCfg.setHostName( ldapConfiguration.getHostName( ) );
+ newCfg.setPort( ldapConfiguration.getPort( ) );
+ newCfg.setProperties( ldapConfiguration.getExtraProperties( ) );
+ newCfg.setSslEnabled( ldapConfiguration.isSsl() );
+ newCfg.setWritable( ldapConfiguration.isWritable() );
+ return newCfg;
+ }
+
+ @Schema(description = "The hostname to use to connect to the LDAP server")
+ public String getHostName( )
+ {
+ return hostName;
+ }
+
+ public void setHostName( String hostName )
+ {
+ this.hostName = hostName;
+ }
+
+ @Schema(description = "The port to use to connect to the LDAP server")
+ public int getPort( )
+ {
+ return port;
+ }
+
+ public void setPort( int port )
+ {
+ this.port = port;
+ }
+
+ @Schema(description = "If SSL should be used for connecting the LDAP server")
+ public boolean isSslEnabled( )
+ {
+ return sslEnabled;
+ }
+
+ public void setSslEnabled( boolean sslEnabled )
+ {
+ this.sslEnabled = sslEnabled;
+ }
+
+ @Schema(description = "The BASE DN used for the LDAP server")
+ public String getBaseDn( )
+ {
+ return baseDn;
+ }
+
+ public void setBaseDn( String baseDn )
+ {
+ this.baseDn = baseDn;
+ }
+
+ @Schema(description = "The distinguished name of the bind user which is used to bind to the LDAP server")
+ public String getBindDn( )
+ {
+ return bindDn;
+ }
+
+ public void setBindDn( String bindDn )
+ {
+ this.bindDn = bindDn;
+ }
+
+ @Schema(description = "The password used to bind to the ldap server")
+ public String getBindPassword( )
+ {
+ return bindPassword;
+ }
+
+ public void setBindPassword( String bindPassword )
+ {
+ this.bindPassword = bindPassword;
+ }
+
+ @Schema(description = "The distinguished name of the base to use for searching group.")
+ public String getGroupsBaseDn( )
+ {
+ return groupsBaseDn;
+ }
+
+ public void setGroupsBaseDn( String groupsBaseDn )
+ {
+ this.groupsBaseDn = groupsBaseDn;
+ }
+
+ @Schema(description = "The authentication method used to bind to the LDAP server (PLAINTEXT, SASL, ...)")
+ public String getAuthenticationMethod( )
+ {
+ return authenticationMethod;
+ }
+
+ public void setAuthenticationMethod( String authenticationMethod )
+ {
+ this.authenticationMethod = authenticationMethod;
+ }
+
+ @Schema(description = "True, if the LDAP bind authentication is used for logging in to Archiva")
+ public boolean isBindAuthenticatorEnabled( )
+ {
+ return bindAuthenticatorEnabled;
+ }
+
+ public void setBindAuthenticatorEnabled( boolean bindAuthenticatorEnabled )
+ {
+ this.bindAuthenticatorEnabled = bindAuthenticatorEnabled;
+ }
+
+ @Schema(description = "True, if the archiva role name is also the LDAP group name")
+ public boolean isUseRoleNameAsGroup( )
+ {
+ return useRoleNameAsGroup;
+ }
+
+ public void setUseRoleNameAsGroup( boolean useRoleNameAsGroup )
+ {
+ this.useRoleNameAsGroup = useRoleNameAsGroup;
+ }
+
+ @Schema(description = "Map of additional properties")
+ public Map<String, String> getProperties( )
+ {
+ return properties;
+ }
+
+ public void setProperties( Map<String, String> properties )
+ {
+ this.properties.clear();
+ this.properties.putAll( properties );
+ }
+
+ @Schema(description = "True, if attributes in the the LDAP server can be edited by Archiva")
+ public boolean isWritable( )
+ {
+ return writable;
+ }
+
+ public void setWritable( boolean writable )
+ {
+ this.writable = writable;
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o ) return true;
+ if ( o == null || getClass( ) != o.getClass( ) ) return false;
+
+ LdapConfiguration that = (LdapConfiguration) o;
+
+ if ( port != that.port ) return false;
+ if ( sslEnabled != that.sslEnabled ) return false;
+ if ( bindAuthenticatorEnabled != that.bindAuthenticatorEnabled ) return false;
+ if ( useRoleNameAsGroup != that.useRoleNameAsGroup ) return false;
+ if ( writable != that.writable ) return false;
+ if ( !Objects.equals( hostName, that.hostName ) ) return false;
+ if ( !Objects.equals( baseDn, that.baseDn ) ) return false;
+ if ( !Objects.equals( bindDn, that.bindDn ) ) return false;
+ if ( !Objects.equals( groupsBaseDn, that.groupsBaseDn ) )
+ return false;
+ if ( !Objects.equals( bindPassword, that.bindPassword ) ) return false;
+ if ( !Objects.equals( authenticationMethod, that.authenticationMethod ) )
+ return false;
+ return properties.equals( that.properties );
+ }
+
+ @Override
+ public int hashCode( )
+ {
+ int result = hostName != null ? hostName.hashCode( ) : 0;
+ result = 31 * result + port;
+ result = 31 * result + ( sslEnabled ? 1 : 0 );
+ result = 31 * result + ( baseDn != null ? baseDn.hashCode( ) : 0 );
+ result = 31 * result + ( bindDn != null ? bindDn.hashCode( ) : 0 );
+ result = 31 * result + ( groupsBaseDn != null ? groupsBaseDn.hashCode( ) : 0 );
+ result = 31 * result + ( bindPassword != null ? bindPassword.hashCode( ) : 0 );
+ result = 31 * result + ( authenticationMethod != null ? authenticationMethod.hashCode( ) : 0 );
+ result = 31 * result + ( bindAuthenticatorEnabled ? 1 : 0 );
+ result = 31 * result + ( useRoleNameAsGroup ? 1 : 0 );
+ result = 31 * result + properties.hashCode( );
+ result = 31 * result + ( writable ? 1 : 0 );
+ return result;
+ }
+
+ @SuppressWarnings( "StringBufferReplaceableByString" )
+ @Override
+ public String toString( )
+ {
+ final StringBuilder sb = new StringBuilder( "LdapConfiguration{" );
+ sb.append( "hostName='" ).append( hostName ).append( '\'' );
+ sb.append( ", port=" ).append( port );
+ sb.append( ", sslEnabled=" ).append( sslEnabled );
+ sb.append( ", baseDn='" ).append( baseDn ).append( '\'' );
+ sb.append( ", groupsBaseDn='" ).append( groupsBaseDn ).append( '\'' );
+ sb.append( ", bindDn='" ).append( bindDn ).append( '\'' );
+ sb.append( ", bindPassword='" ).append( bindPassword ).append( '\'' );
+ sb.append( ", authenticationMethod='" ).append( authenticationMethod ).append( '\'' );
+ sb.append( ", bindAuthenticatorEnabled=" ).append( bindAuthenticatorEnabled );
+ sb.append( ", useRoleNameAsGroup=" ).append( useRoleNameAsGroup );
+ sb.append( ", properties=" ).append( properties );
+ sb.append( ", writable=" ).append( writable );
+ sb.append( '}' );
+ return sb.toString( );
+ }
+}
--- /dev/null
+package org.apache.archiva.rest.api.model.v2;/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.archiva.admin.model.beans.RedbackRuntimeConfiguration;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@XmlRootElement(name = "securityConfiguration")
+public class SecurityConfiguration implements Serializable
+{
+ private static final long serialVersionUID = -4186866365979053029L;
+
+ private final List<String> activeUserManagers = new ArrayList<>( );
+ private final List<String> activeRbacManagers = new ArrayList<>( );
+ private final Map<String,String> properties = new TreeMap<>( );
+ private boolean userCacheEnabled=false;
+ private boolean ldapActive=false;
+
+ public SecurityConfiguration() {
+
+ }
+
+ public static SecurityConfiguration ofRedbackConfiguration( RedbackRuntimeConfiguration configuration ) {
+ SecurityConfiguration secConfig = new SecurityConfiguration( );
+ secConfig.setActiveRbacManagers( configuration.getRbacManagerImpls() );
+ secConfig.setActiveUserManagers( configuration.getUserManagerImpls() );
+ secConfig.setProperties( configuration.getConfigurationProperties() );
+ boolean rbLdapActive = configuration.getUserManagerImpls( ).stream( ).anyMatch( um -> um.contains( "ldap" ) );
+ secConfig.setLdapActive( rbLdapActive );
+ secConfig.setUserCacheEnabled( configuration.isUseUsersCache() );
+ return secConfig;
+ }
+
+ @Schema(description = "List of ids of the active user managers")
+ public List<String> getActiveUserManagers( )
+ {
+ return activeUserManagers;
+ }
+
+ public void setActiveUserManagers( List<String> activeUserManagers )
+ {
+ this.activeUserManagers.clear();
+ this.activeUserManagers.addAll( activeUserManagers );
+ }
+
+ public void addSelectedUserManager(String userManager) {
+ this.activeUserManagers.add( userManager );
+ }
+
+ @Schema(description = "List of ids of the active rbac managers")
+ public List<String> getActiveRbacManagers( )
+ {
+ return activeRbacManagers;
+ }
+
+ public void setActiveRbacManagers( List<String> activeRbacManagers )
+ {
+ this.activeRbacManagers.clear();
+ this.activeRbacManagers.addAll( activeRbacManagers );
+ }
+
+ public void addSelectedRbacManager(String rbacManager) {
+ this.activeRbacManagers.add( rbacManager );
+ }
+
+ @Schema(description = "Map of all security properties")
+ public Map<String, String> getProperties( )
+ {
+ return properties;
+ }
+
+ public void setProperties( Map<String, String> properties )
+ {
+ this.properties.clear();
+ this.properties.putAll( properties );
+ }
+
+ @Schema(description = "True, if the user cache is active. It caches data from user backend.")
+ public boolean isUserCacheEnabled( )
+ {
+ return userCacheEnabled;
+ }
+
+ public void setUserCacheEnabled( boolean userCacheEnabled )
+ {
+ this.userCacheEnabled = userCacheEnabled;
+ }
+
+ @Schema(description = "True, if LDAP is used as user manager")
+ public boolean isLdapActive( )
+ {
+ return ldapActive;
+ }
+
+ public void setLdapActive( boolean ldapActive )
+ {
+ this.ldapActive = ldapActive;
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o ) return true;
+ if ( o == null || getClass( ) != o.getClass( ) ) return false;
+
+ SecurityConfiguration that = (SecurityConfiguration) o;
+
+ if ( userCacheEnabled != that.userCacheEnabled ) return false;
+ if ( ldapActive != that.ldapActive ) return false;
+ if ( !activeUserManagers.equals( that.activeUserManagers ) ) return false;
+ if ( !activeRbacManagers.equals( that.activeRbacManagers ) ) return false;
+ return properties.equals( that.properties );
+ }
+
+ @Override
+ public int hashCode( )
+ {
+ int result = activeUserManagers.hashCode( );
+ result = 31 * result + activeRbacManagers.hashCode( );
+ result = 31 * result + properties.hashCode( );
+ result = 31 * result + ( userCacheEnabled ? 1 : 0 );
+ result = 31 * result + ( ldapActive ? 1 : 0 );
+ return result;
+ }
+
+ @SuppressWarnings( "StringBufferReplaceableByString" )
+ @Override
+ public String toString( )
+ {
+ final StringBuilder sb = new StringBuilder( "SecurityConfiguration{" );
+ sb.append( "selectedUserManagers=" ).append( activeUserManagers );
+ sb.append( ", selectedRbacManagers=" ).append( activeRbacManagers );
+ sb.append( ", properties=" ).append( properties );
+ sb.append( ", userCacheEnabled=" ).append( userCacheEnabled );
+ sb.append( ", ldapActive=" ).append( ldapActive );
+ sb.append( '}' );
+ return sb.toString( );
+ }
+}
--- /dev/null
+package org.apache.archiva.rest.api.services.v2;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Martin Stockhammer
+ * @since 3.0
+ */
+@XmlRootElement( name = "archivaRestError" )
+@Schema(name="ArchivaRestError", description = "Contains a list of error messages that resulted from the current REST call")
+public class ArchivaRestError
+ implements Serializable
+{
+
+ private static final long serialVersionUID = -8892617571273167067L;
+ private List<ErrorMessage> errorMessages = new ArrayList<ErrorMessage>( 1 );
+
+ public ArchivaRestError()
+ {
+ // no op
+ }
+
+ public ArchivaRestError( ArchivaRestServiceException e )
+ {
+ errorMessages.addAll( e.getErrorMessages() );
+ if ( e.getErrorMessages().isEmpty() && StringUtils.isNotEmpty( e.getMessage() ) )
+ {
+ errorMessages.add( new ErrorMessage( e.getMessage(), null ) );
+ }
+ }
+
+ @Schema(name="errorMessages", description = "The list of errors that occurred while processing the REST request")
+ public List<ErrorMessage> getErrorMessages()
+ {
+ return errorMessages;
+ }
+
+ public void setErrorMessages( List<ErrorMessage> errorMessages )
+ {
+ this.errorMessages = errorMessages;
+ }
+
+ public void addErrorMessage( ErrorMessage errorMessage )
+ {
+ this.errorMessages.add( errorMessage );
+ }
+}
--- /dev/null
+package org.apache.archiva.rest.api.services.v2;/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Generic REST Service Exception that contains error information.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ * @since 3.0
+ */
+public class ArchivaRestServiceException extends Exception
+{
+ private int httpErrorCode = 500;
+
+ private List<ErrorMessage> errorMessages = new ArrayList<ErrorMessage>(0);
+
+ public ArchivaRestServiceException( String s )
+ {
+ super( s );
+ }
+
+ public ArchivaRestServiceException( String s, int httpErrorCode )
+ {
+ super( s );
+ this.httpErrorCode = httpErrorCode;
+ }
+
+ public ArchivaRestServiceException( ErrorMessage errorMessage )
+ {
+ errorMessages.add( errorMessage );
+ }
+
+ public ArchivaRestServiceException( ErrorMessage errorMessage, int httpResponseCode )
+ {
+ this.httpErrorCode = httpResponseCode;
+ errorMessages.add( errorMessage );
+ }
+
+ public ArchivaRestServiceException( List<ErrorMessage> errorMessage )
+ {
+ errorMessages.addAll( errorMessage );
+ }
+
+ public ArchivaRestServiceException( List<ErrorMessage> errorMessage, int httpResponseCode )
+ {
+ this.httpErrorCode = httpResponseCode;
+ errorMessages.addAll( errorMessage );
+ }
+
+ public int getHttpErrorCode()
+ {
+ return httpErrorCode;
+ }
+
+ public void setHttpErrorCode( int httpErrorCode )
+ {
+ this.httpErrorCode = httpErrorCode;
+ }
+
+ public List<ErrorMessage> getErrorMessages()
+ {
+ if ( errorMessages == null )
+ {
+ this.errorMessages = new ArrayList<ErrorMessage>();
+ }
+ return errorMessages;
+ }
+
+ public void setErrorMessages( List<ErrorMessage> errorMessages )
+ {
+ this.errorMessages = errorMessages;
+ }
+
+ public void addErrorMessage( ErrorMessage errorMessage )
+ {
+ this.errorMessages.add( errorMessage );
+ }
+
+}
--- /dev/null
+package org.apache.archiva.rest.api.services.v2;/*
+ * 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.
+ */
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public interface Configuration
+{
+ String DEFAULT_PAGE_LIMIT = "10";
+}
--- /dev/null
+package org.apache.archiva.rest.api.services.v2;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+/**
+ * @author Olivier Lamy
+ * @author Martin Stockhammer
+ * @since 3.0
+ */
+@XmlRootElement( name = "errorMessage" )
+@Schema(name="ErrorMessage",description = "Information about the error, that occurred while processing the REST request.")
+public class ErrorMessage
+ implements Serializable
+{
+ private String errorKey = "";
+
+ private String[] args = EMPTY;
+
+ private String message = "";
+
+ private static final String[] EMPTY = new String[0];
+
+ public ErrorMessage()
+ {
+ // no op
+ }
+
+ public ErrorMessage( String errorKey )
+ {
+ this.errorKey = errorKey;
+ this.args = EMPTY;
+ }
+
+ public ErrorMessage( String errorKey, String[] args )
+ {
+ this.errorKey = errorKey;
+ this.args = args;
+ }
+
+ public static ErrorMessage of(String errorKey, String... args) {
+ return new ErrorMessage( errorKey, args );
+ }
+
+ @Schema(description = "The key of the error message. If this is empty, the message message must be set.")
+ public String getErrorKey()
+ {
+ return errorKey;
+ }
+
+ public void setErrorKey( String errorKey )
+ {
+ this.errorKey = errorKey;
+ }
+
+ @Schema(description = "Parameters that can be filled to the translated error message")
+ public String[] getArgs()
+ {
+ return args;
+ }
+
+ public void setArgs( String[] args )
+ {
+ this.args = args;
+ }
+
+ @Schema(description = "Full error message. Either additional to the key in the default language, or if the message is without key.")
+ public String getMessage()
+ {
+ return message;
+ }
+
+ public void setMessage( String message )
+ {
+ this.message = message;
+ }
+
+ public ErrorMessage message( String message )
+ {
+ this.message = message;
+ return this;
+ }
+}
* under the License.
*/
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.apache.archiva.components.rest.model.PagedResult;
+import org.apache.archiva.components.rest.model.PropertyEntry;
+import org.apache.archiva.redback.authorization.RedbackAuthorization;
+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.model.v2.SecurityConfiguration;
+import org.apache.archiva.security.common.ArchivaRoleConstants;
+
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.apache.archiva.rest.api.services.v2.Configuration.DEFAULT_PAGE_LIMIT;
+
/**
*
* Service for configuration of redback and security related settings.
* @author Martin Stockhammer <martin_s@apache.org>
* @since 3.0
*/
+@Path( "/security" )
+@Tag(name = "v2")
+@Tag(name = "v2/Security")
+@SecurityRequirement(name = "BearerAuth")
public interface SecurityConfigurationService
{
+ @Path("config")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON })
+ @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION)
+ @Operation( summary = "Returns the security configuration that is currently active.",
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ description = "If the configuration could be retrieved"
+ ),
+ @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+ content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) )
+ }
+ )
+ SecurityConfiguration getConfiguration()
+ throws ArchivaRestServiceException;
+
+ @GET
+ @Produces( { APPLICATION_JSON } )
+ @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
+ @Operation( summary = "Returns all configuration properties. The result is paged.",
+ parameters = {
+ @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 = "order", description = "The sort order. Either ascending (asc) or descending (desc)")
+ },
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ description = "If the list could be returned",
+ content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class))
+ ),
+ @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+ content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) )
+ }
+ )
+ 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("order") @DefaultValue( "asc" ) String order ) throws ArchivaRestServiceException;
+
+ @Path("ldap")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON })
+ @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION)
+ @Operation( summary = "Returns the LDAP configuration that is currently active.",
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ description = "If the configuration could be retrieved"
+ ),
+ @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+ content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) )
+ }
+ )
+ LdapConfiguration getLdapConfiguration( ) throws ArchivaRestServiceException;
+
+
+ @Path("user/cache")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON })
+ @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION)
+ @Operation( summary = "Returns the cache configuration that is currently active.",
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ description = "If the configuration could be retrieved"
+ ),
+ @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+ content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) )
+ }
+ )
+ CacheConfiguration getCacheConfiguration( ) throws ArchivaRestServiceException;
+
+ @Path("user/managers")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON })
+ @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION)
+ @Operation( summary = "Returns the available user manager implementations.",
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ description = "If the list could be retrieved"
+ ),
+ @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+ content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) )
+ }
+ )
+ List<BeanInformation> getAvailableUserManagers()
+ throws ArchivaRestServiceException;
+
+ @Path("rbac/managers")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON })
+ @RedbackAuthorization(permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION)
+ @Operation( summary = "Returns the available RBAC manager implementations.",
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ description = "If the list could be retrieved"
+ ),
+ @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+ content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestServiceException.class )) )
+ }
+ )
+ List<BeanInformation> getAvailableRbacManagers()
+ throws ArchivaRestServiceException;
+
}
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-features-logging</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-extension-providers</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+
<!-- TEST Scope -->
<dependency>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>rest-assured</artifactId>
+ <scope>test</scope>
+ </dependency>
+
<!-- Needed for JDK >= 9 -->
<dependency>
--- /dev/null
+package org.apache.archiva.rest.services.interceptors.v2;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.archiva.rest.api.services.v2.ArchivaRestError;
+import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException;
+import org.springframework.stereotype.Service;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+/**
+ * Maps exceptions to REST responses.
+ *
+ * @author Martin Stockhammer
+ * @since 3.0
+ */
+@Provider
+@Service( "v2.archivaRestServiceExceptionMapper" )
+public class ArchivaRestServiceExceptionMapper
+ implements ExceptionMapper<ArchivaRestServiceException>
+{
+ @Override
+ public Response toResponse( final ArchivaRestServiceException e )
+ {
+ ArchivaRestError restError = new ArchivaRestError( e );
+
+ Response.ResponseBuilder responseBuilder = Response.status( e.getHttpErrorCode() ).entity( restError );
+ if ( e.getMessage() != null )
+ {
+ responseBuilder = responseBuilder.status( new Response.StatusType()
+ {
+ public int getStatusCode()
+ {
+ return e.getHttpErrorCode();
+ }
+
+ public Response.Status.Family getFamily()
+ {
+ return Response.Status.Family.SERVER_ERROR;
+ }
+
+ public String getReasonPhrase()
+ {
+ return e.getMessage();
+ }
+ } );
+ }
+ return responseBuilder.build();
+ }
+}
--- /dev/null
+package org.apache.archiva.rest.services.v2;/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.archiva.admin.model.RepositoryAdminException;
+import org.apache.archiva.admin.model.beans.RedbackRuntimeConfiguration;
+import org.apache.archiva.admin.model.runtime.RedbackRuntimeConfigurationAdmin;
+import org.apache.archiva.components.rest.model.PagedResult;
+import org.apache.archiva.components.rest.model.PropertyEntry;
+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.model.v2.SecurityConfiguration;
+import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException;
+import org.apache.archiva.rest.api.services.v2.ErrorMessage;
+import org.apache.archiva.rest.api.services.v2.SecurityConfigurationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.inject.Inject;
+import java.util.List;
+
+import static org.apache.archiva.rest.services.v2.ErrorKeys.REPOSITORY_ADMIN_ERROR;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@Service("v2.defaultSecurityConfigurationService")
+public class DefaultSecurityConfigurationService implements SecurityConfigurationService
+{
+ private static final Logger log = LoggerFactory.getLogger( DefaultSecurityConfigurationService.class );
+
+ @Inject
+ private RedbackRuntimeConfigurationAdmin redbackRuntimeConfigurationAdmin;
+
+ @Override
+ public SecurityConfiguration getConfiguration( ) throws ArchivaRestServiceException
+ {
+ try
+ {
+ RedbackRuntimeConfiguration redbackRuntimeConfiguration =
+ redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration();
+
+ log.debug( "getRedbackRuntimeConfiguration -> {}", redbackRuntimeConfiguration );
+
+ return SecurityConfiguration.ofRedbackConfiguration( redbackRuntimeConfiguration );
+ }
+ catch ( RepositoryAdminException e )
+ {
+ throw new ArchivaRestServiceException( ErrorMessage.of( REPOSITORY_ADMIN_ERROR ) );
+ }
+ }
+
+ @Override
+ public PagedResult<PropertyEntry> getConfigurationProperties( String searchTerm, Integer offset, Integer limit, List<String> orderBy, String order ) throws ArchivaRestServiceException
+ {
+ return null;
+ }
+
+ @Override
+ public LdapConfiguration getLdapConfiguration( ) throws ArchivaRestServiceException
+ {
+ return null;
+ }
+
+ @Override
+ public CacheConfiguration getCacheConfiguration( ) throws ArchivaRestServiceException
+ {
+ return null;
+ }
+
+ @Override
+ public List<BeanInformation> getAvailableUserManagers( ) throws ArchivaRestServiceException
+ {
+ return null;
+ }
+
+ @Override
+ public List<BeanInformation> getAvailableRbacManagers( ) throws ArchivaRestServiceException
+ {
+ return null;
+ }
+}
--- /dev/null
+package org.apache.archiva.rest.services.v2;/*
+ * 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.
+ */
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public interface ErrorKeys
+{
+ public static final String REPOSITORY_ADMIN_ERROR = "a.repositoryadmin.error";
+
+}
<context:component-scan
base-package="org.apache.archiva.rest.services,org.apache.archiva.redback.rest.services"/>
+ <!-- CXF OpenApiFeature -->
+ <bean id="archivaOpenApiFeature" class="org.apache.cxf.jaxrs.openapi.OpenApiFeature">
+ <property name="scanKnownConfigLocations" value="false"/>
+ <property name="configLocation" value="archiva/openapi-configuration.yaml"/>
+ <property name="scan" value="false"/>
+ <property name="useContextBasedConfig" value="true"/>
+ <!-- <property name="scannerClass" value="io.swagger.v3.jaxrs2.integration.JaxrsApplicationScanner"/> -->
+ </bean>
+
+
<bean id="jsonProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider">
<property name="mapper" ref="redbackJacksonJsonMapper"/>
</bean>
+ <bean id="v2.jsonProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider">
+ <property name="mapper" ref="v2.redbackJacksonJsonMapper"/>
+ </bean>
+
<bean id="xmlProvider" class="com.fasterxml.jackson.jaxrs.xml.JacksonJaxbXMLProvider">
<property name="mapper" ref="redbackJacksonXMLMapper"/>
</bean>
<bean id="redbackJacksonJsonMapper" class="com.fasterxml.jackson.databind.ObjectMapper" />
+ <bean id="v2.redbackJacksonJsonMapper" class="com.fasterxml.jackson.databind.ObjectMapper" >
+ </bean>
<bean id="redbackJacksonXMLMapper" class="com.fasterxml.jackson.dataformat.xml.XmlMapper" />
</jaxrs:server>
+
+ <jaxrs:server name="v2.archiva" address="/v2/archiva" >
+
+ <jaxrs:providers>
+ <ref bean="v2.jsonProvider" />
+ <ref bean="bearerAuthInterceptor#rest"/>
+ <ref bean="permissionInterceptor#rest"/>
+ <ref bean="requestValidationInterceptor#rest" />
+ <ref bean="v2.archivaRestServiceExceptionMapper"/>
+ <ref bean="threadLocalUserCleaner#rest" />
+ </jaxrs:providers>
+
+ <jaxrs:serviceBeans>
+ <ref bean="v2.defaultSecurityConfigurationService" />
+ </jaxrs:serviceBeans>
+
+ <jaxrs:features>
+ <ref bean="archivaOpenApiFeature" />
+ </jaxrs:features>
+
+ </jaxrs:server>
+
+
<bean name="browse#versionMetadata" class="org.apache.archiva.components.cache.ehcache.EhcacheCache"
init-method="initialize">
<property name="diskPersistent" value="false"/>
--- /dev/null
+package org.apache.archiva.rest.services.v2;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import io.restassured.RestAssured;
+import io.restassured.builder.RequestSpecBuilder;
+import io.restassured.config.ObjectMapperConfig;
+import io.restassured.config.RestAssuredConfig;
+import io.restassured.path.json.mapper.factory.Jackson2ObjectMapperFactory;
+import io.restassured.response.Response;
+import io.restassured.specification.RequestSpecification;
+import org.apache.archiva.redback.integration.security.role.RedbackRoleConstants;
+import org.apache.archiva.redback.rest.services.BaseSetup;
+import org.apache.archiva.redback.role.RoleManager;
+import org.apache.archiva.redback.role.RoleManagerException;
+import org.apache.archiva.redback.users.User;
+import org.apache.archiva.redback.users.UserManager;
+import org.apache.archiva.redback.users.UserManagerException;
+import org.apache.archiva.redback.users.UserNotFoundException;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.cxf.transport.servlet.CXFServlet;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.junit.jupiter.api.Tag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.context.ContextLoaderListener;
+
+import java.lang.reflect.Type;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalTime;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static io.restassured.RestAssured.*;
+import static io.restassured.http.ContentType.JSON;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+/**
+ * Native REST tests do not use the JAX-RS client and can be used with a remote
+ * REST API service. The tests
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@Tag( "rest-native" )
+@Tag( "rest-v2" )
+public abstract class AbstractNativeRestServices
+{
+ private AtomicReference<Path> projectDir = new AtomicReference<>();
+ private AtomicReference<Path> appServerBase = new AtomicReference<>( );
+ private AtomicReference<Path> basePath = new AtomicReference<>( );
+
+ public static final int STOPPED = 0;
+ public static final int STOPPING = 1;
+ public static final int STARTING = 2;
+ public static final int STARTED = 3;
+ public static final int ERROR = 4;
+ private final boolean startServer;
+ private final String serverPort;
+ private final String baseUri;
+
+ private RequestSpecification requestSpec;
+ protected Logger log = LoggerFactory.getLogger( getClass( ) );
+
+ private static AtomicReference<Server> server = new AtomicReference<>( );
+ private static AtomicReference<ServerConnector> serverConnector = new AtomicReference<>( );
+ private static AtomicInteger serverStarted = new AtomicInteger( STOPPED );
+ private UserManager userManager;
+ private RoleManager roleManager;
+
+ private final boolean remoteService;
+
+ private String adminToken;
+ private String adminRefreshToken;
+
+
+ public AbstractNativeRestServices( )
+ {
+ this.startServer = BaseSetup.startServer( );
+ this.serverPort = BaseSetup.getServerPort( );
+ this.baseUri = BaseSetup.getBaseUri( );
+
+ if ( startServer )
+ {
+ this.remoteService = false;
+ } else {
+ this.remoteService = true;
+ }
+ }
+
+ protected abstract String getServicePath( );
+
+ protected String getSpringConfigLocation( )
+ {
+ return "classpath*:META-INF/spring-context.xml,classpath:META-INF/spring-context-native-test.xml";
+ }
+
+ protected RequestSpecification getRequestSpec( )
+ {
+ return this.requestSpec;
+ }
+
+ protected String getContextRoot( )
+ {
+ return "/api";
+ }
+
+
+ protected String getServiceBasePath( )
+ {
+ return "/v2/archiva";
+ }
+
+ protected String getRedbackServiceBasePath( )
+ {
+ return "/v2/redback";
+ }
+
+
+ protected String getBasePath( )
+ {
+ return new StringBuilder( )
+ .append( getContextRoot( ) )
+ .append( getServiceBasePath( ) )
+ .append( getServicePath( ) ).toString( );
+ }
+
+ /**
+ * Returns the server that was started, or null if not initialized before.
+ *
+ * @return
+ */
+ public Server getServer( )
+ {
+ return this.server.get( );
+ }
+
+ public int getServerPort( )
+ {
+ ServerConnector connector = serverConnector.get( );
+ if ( connector != null )
+ {
+ return connector.getLocalPort( );
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /**
+ * Returns true, if the server does exist and is running.
+ *
+ * @return true, if server does exist and is running.
+ */
+ public boolean isServerRunning( )
+ {
+ return serverStarted.get( ) == STARTED && this.server.get( ) != null && this.server.get( ).isRunning( );
+ }
+
+ private UserManager getUserManager( )
+ {
+ if ( this.userManager == null )
+ {
+ UserManager userManager = ContextLoaderListener.getCurrentWebApplicationContext( )
+ .getBean( "userManager#default", UserManager.class );
+ assertNotNull( userManager );
+ this.userManager = userManager;
+ }
+ return this.userManager;
+ }
+
+ private RoleManager getRoleManager( )
+ {
+ if ( this.roleManager == null )
+ {
+ RoleManager roleManager = ContextLoaderListener.getCurrentWebApplicationContext( )
+ .getBean( "roleManager", RoleManager.class );
+ assertNotNull( roleManager );
+ this.roleManager = roleManager;
+ }
+ return this.roleManager;
+ }
+
+ protected String getAdminPwd( )
+ {
+ return BaseSetup.getAdminPwd( );
+ }
+
+ protected String getAdminUser( )
+ {
+ return RedbackRoleConstants.ADMINISTRATOR_ACCOUNT_NAME;
+ }
+
+ private void setupAdminUser( ) throws UserManagerException, RoleManagerException
+ {
+
+ UserManager um = getUserManager( );
+
+ User adminUser = null;
+ try
+ {
+ adminUser = um.findUser( getAdminUser( ) );
+ }
+ catch ( UserNotFoundException e )
+ {
+ // ignore
+ }
+ adminUser = um.createUser( getAdminUser( ), "Administrator", "admin@local.home" );
+ adminUser.setUsername( getAdminUser( ) );
+ adminUser.setPassword( getAdminPwd( ) );
+ adminUser.setFullName( "the admin user" );
+ adminUser.setEmail( "toto@toto.fr" );
+ adminUser.setPermanent( true );
+ adminUser.setValidated( true );
+ adminUser.setLocked( false );
+ adminUser.setPasswordChangeRequired( false );
+ if ( adminUser == null )
+ {
+ um.addUser( adminUser );
+ }
+ else
+ {
+ um.updateUser( adminUser, false );
+ }
+ getRoleManager( ).assignRole( "system-administrator", adminUser.getUsername( ) );
+ }
+
+ protected Path getProjectDirectory() {
+ if ( projectDir.get()==null) {
+ String propVal = System.getProperty("mvn.project.base.dir");
+ Path newVal;
+ if (StringUtils.isEmpty(propVal)) {
+ newVal = Paths.get("").toAbsolutePath();
+ } else {
+ newVal = Paths.get(propVal).toAbsolutePath();
+ }
+ projectDir.compareAndSet(null, newVal);
+ }
+ return projectDir.get();
+ }
+
+ public Path getBasedir()
+ {
+ if (basePath.get()==null) {
+ String baseDir = System.getProperty( "basedir" );
+ final Path baseDirPath;
+ if (StringUtils.isNotEmpty( baseDir )) {
+ baseDirPath = Paths.get( baseDir );
+ } else {
+ baseDirPath = getProjectDirectory( );
+ }
+ basePath.compareAndSet( null, baseDirPath );
+ }
+ return basePath.get( );
+ }
+
+ Path getAppserverBase() {
+ if (appServerBase.get()==null) {
+ String basePath = System.getProperty( "appserver.base" );
+ final Path appserverPath;
+ if (StringUtils.isNotEmpty( basePath )) {
+ appserverPath = Paths.get( basePath ).toAbsolutePath( );
+ } else {
+ appserverPath = getBasedir( ).resolve( "target" ).resolve( "appserver-base-" + LocalTime.now( ).toSecondOfDay( ) );
+ }
+ appServerBase.compareAndSet( null, appserverPath );
+ }
+ return appServerBase.get();
+ }
+
+ private void removeAppsubFolder( Path appServerBase, String folder )
+ throws Exception
+ {
+ Path directory = appServerBase.resolve( folder );
+ if ( Files.exists(directory) )
+ {
+ org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
+ }
+ }
+
+ public void startServer( )
+ throws Exception
+ {
+ if ( serverStarted.compareAndSet( STOPPED, STARTING ) )
+ {
+ try
+ {
+ log.info( "Starting server" );
+ Path appServerBase = getAppserverBase( );
+
+ removeAppsubFolder(appServerBase, "jcr");
+ removeAppsubFolder(appServerBase, "conf");
+ removeAppsubFolder(appServerBase, "data");
+
+
+ Server myServer = new Server( );
+ this.server.set( myServer );
+ this.serverConnector.set( new ServerConnector( myServer, new HttpConnectionFactory( ) ) );
+ myServer.addConnector( serverConnector.get( ) );
+
+ ServletHolder servletHolder = new ServletHolder( new CXFServlet( ) );
+ ServletContextHandler context = new ServletContextHandler( ServletContextHandler.SESSIONS );
+ context.setResourceBase( SystemUtils.JAVA_IO_TMPDIR );
+ context.setSessionHandler( new SessionHandler( ) );
+ context.addServlet( servletHolder, getContextRoot( ) + "/*" );
+ context.setInitParameter( "contextConfigLocation", getSpringConfigLocation( ) );
+ context.addEventListener( new ContextLoaderListener( ) );
+
+ getServer( ).setHandler( context );
+ getServer( ).start( );
+
+ if ( log.isDebugEnabled( ) )
+ {
+ log.debug( "Jetty dump: {}", getServer( ).dump( ) );
+ }
+
+ setupAdminUser( );
+ log.info( "Started server on port {}", getServerPort( ) );
+ serverStarted.set( STARTED );
+ }
+ finally
+ {
+ // In case, if the last statement was not reached
+ serverStarted.compareAndSet( STARTING, ERROR );
+ }
+ }
+
+ }
+
+ public void stopServer( )
+ throws Exception
+ {
+ if ( this.serverStarted.compareAndSet( STARTED, STOPPING ) )
+ {
+ try
+ {
+ final Server myServer = getServer( );
+ if ( myServer != null )
+ {
+ log.info( "Stopping server" );
+ myServer.stop( );
+ }
+ serverStarted.set( STOPPED );
+ }
+ finally
+ {
+ serverStarted.compareAndSet( STOPPING, ERROR );
+ }
+ }
+ else
+ {
+ log.error( "Serer is not in STARTED state!" );
+ }
+ }
+
+
+ protected void setupNative( ) throws Exception
+ {
+ if ( this.startServer )
+ {
+ startServer( );
+ }
+
+ if ( StringUtils.isNotEmpty( serverPort ) )
+ {
+ RestAssured.port = Integer.parseInt( serverPort );
+ }
+ else
+ {
+ RestAssured.port = getServerPort( );
+ }
+ if ( StringUtils.isNotEmpty( baseUri ) )
+ {
+ RestAssured.baseURI = baseUri;
+ }
+ else
+ {
+ RestAssured.baseURI = "http://localhost";
+ }
+ String basePath = getBasePath( );
+ this.requestSpec = getRequestSpecBuilder( ).build( );
+ RestAssured.basePath = basePath;
+ RestAssured.config = RestAssuredConfig.config().objectMapperConfig(new ObjectMapperConfig().jackson2ObjectMapperFactory(
+ new Jackson2ObjectMapperFactory() {
+ @Override
+ public ObjectMapper create( Type cls, String charset) {
+ ObjectMapper om = new ObjectMapper().findAndRegisterModules();
+ om.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ om.setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE );
+ return om;
+ }
+
+ }
+ ));
+ }
+
+ protected RequestSpecBuilder getRequestSpecBuilder( ) {
+ return getRequestSpecBuilder( null );
+ }
+
+ protected RequestSpecBuilder getRequestSpecBuilder( String basePath )
+ {
+ String myBasePath = basePath == null ? getBasePath( ) : basePath;
+ return new RequestSpecBuilder( ).setBaseUri( baseURI )
+ .setPort( port )
+ .setBasePath( myBasePath )
+ .addHeader( "Origin", RestAssured.baseURI + ":" + RestAssured.port );
+ }
+
+ protected RequestSpecBuilder getAuthRequestSpecBuilder( )
+ {
+ return new RequestSpecBuilder( ).setBaseUri( baseURI )
+ .setPort( port )
+ .setBasePath( new StringBuilder( )
+ .append( getContextRoot( ) )
+ .append( getRedbackServiceBasePath() ).append("/auth").toString() )
+ .addHeader( "Origin", RestAssured.baseURI + ":" + RestAssured.port );
+ }
+
+ protected RequestSpecification getRequestSpec( String bearerToken )
+ {
+ return getRequestSpecBuilder( ).addHeader( "Authorization", "Bearer " + bearerToken ).build( );
+ }
+
+ protected RequestSpecification getRequestSpec( String bearerToken, String path)
+ {
+ return getRequestSpecBuilder( path ).addHeader( "Authorization", "Bearer " + bearerToken ).build( );
+ }
+
+ protected void shutdownNative( ) throws Exception
+ {
+ if (startServer)
+ {
+ stopServer( );
+ }
+ }
+
+ protected org.apache.archiva.redback.rest.api.model.User addRemoteUser(String userid, String password, String fullName, String mail) {
+
+ return null;
+ }
+
+ protected void initAdminToken() {
+ Map<String, Object> jsonAsMap = new HashMap<>();
+ jsonAsMap.put( "grant_type", "authorization_code" );
+ jsonAsMap.put("user_id", getAdminUser());
+ jsonAsMap.put("password", getAdminPwd() );
+ Response result = given( ).spec( getAuthRequestSpecBuilder().build() )
+ .contentType( JSON )
+ .body( jsonAsMap )
+ .when( ).post( "/authenticate").then( ).statusCode( 200 )
+ .extract( ).response( );
+ this.adminToken = result.body( ).jsonPath( ).getString( "access_token" );
+ this.adminRefreshToken = result.body( ).jsonPath( ).getString( "refresh_token" );
+ }
+
+ protected String getUserToken(String userId, String password) {
+ Map<String, Object> jsonAsMap = new HashMap<>();
+ jsonAsMap.put( "grant_type", "authorization_code" );
+ jsonAsMap.put("user_id", userId);
+ jsonAsMap.put("password", password );
+ Response result = given( ).spec( getAuthRequestSpecBuilder().build() )
+ .contentType( JSON )
+ .body( jsonAsMap )
+ .when( ).post( "/authenticate").prettyPeek().then( ).statusCode( 200 )
+ .extract( ).response( );
+ result.getBody( ).prettyPrint( );
+ return result.body( ).jsonPath( ).getString( "access_token" );
+ }
+ protected String getAdminToken() {
+ if (this.adminToken == null) {
+ initAdminToken();
+ }
+ return this.adminToken;
+ }
+
+
+ protected String getAdminRefreshToken() {
+ if (this.adminRefreshToken == null) {
+ initAdminToken();
+ }
+ return this.adminRefreshToken;
+ }
+
+ public boolean isRemoteService() {
+ return this.remoteService;
+ }
+}
--- /dev/null
+package org.apache.archiva.rest.services.v2;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import io.restassured.response.Response;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import static io.restassured.RestAssured.given;
+import static io.restassured.http.ContentType.JSON;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@TestInstance( TestInstance.Lifecycle.PER_CLASS )
+@Tag( "rest-native" )
+@TestMethodOrder( MethodOrderer.Random.class )
+@DisplayName( "Native REST tests for V2 SecurityConfigurationService" )
+public class NativeSecurityConfigurationServiceTest extends AbstractNativeRestServices
+{
+ @Override
+ protected String getServicePath( )
+ {
+ return "/security";
+ }
+
+ @BeforeAll
+ void setup( ) throws Exception
+ {
+ super.setupNative( );
+ }
+
+ @AfterAll
+ void destroy( ) throws Exception
+ {
+ super.shutdownNative( );
+ }
+
+ @Test
+ void testGetConfiguration() {
+ String token = getAdminToken( );
+ 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]" ) );
+ assertEquals( "jpa", response.getBody( ).jsonPath( ).getString( "active_rbac_managers[0]" ) );
+ assertEquals( "memory", response.getBody( ).jsonPath( ).getString( "properties.\"authentication.jwt.keystoreType\"" ) );
+ assertEquals("10",response.getBody( ).jsonPath( ).getString( "properties.\"security.policy.allowed.login.attempt\""));
+ assertTrue( response.getBody( ).jsonPath( ).getBoolean( "user_cache_enabled" ) );
+ assertFalse( response.getBody( ).jsonPath( ).getBoolean( "ldap_active" ) );
+ }
+
+}
--- /dev/null
+<?xml version="1.0"?>
+
+<!--
+ ~ 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.
+ -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:tx="http://www.springframework.org/schema/tx"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context-3.0.xsd
+
+ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
+ default-lazy-init="true">
+
+ <context:annotation-config/>
+ <context:component-scan
+ base-package="org.apache.archiva.redback.configuration,org.apache.archiva.redback.keys,org.apache.archiva.rest.services.utils,org.apache.archiva.repository.content"/>
+
+ <bean name="scheduler" class="org.apache.archiva.components.scheduler.DefaultScheduler">
+ <property name="properties">
+ <props>
+ <prop key="org.quartz.scheduler.instanceName">scheduler1</prop>
+ <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
+ <prop key="org.quartz.threadPool.threadCount">2</prop>
+ <prop key="org.quartz.threadPool.threadPriority">4</prop>
+ <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>
+ </props>
+ </property>
+ </bean>
+
+ <!-- wire up more basic configuration so it doesn't overwrite any config files -->
+ <bean name="archivaConfiguration#default" class="org.apache.archiva.configuration.DefaultArchivaConfiguration">
+ <property name="registry" ref="registry#default"/>
+ </bean>
+
+ <alias name="archivaConfiguration#default" alias="archivaConfiguration"/>
+
+ <bean name="registry#default" class="org.apache.archiva.components.registry.commons.CommonsConfigurationRegistry">
+ <property name="initialConfiguration">
+ <value>
+ <![CDATA[
+ <configuration>
+ <system/>
+ <xml fileName="${appserver.base}/conf/archiva.xml" config-forceCreate="true"
+ config-optional="true"
+ config-name="org.apache.archiva.base" config-at="org.apache.archiva"/>
+ <properties fileName="${basedir}/src/test/resources/security.properties" config-optional="true"
+ config-at="org.apache.archiva.redback"/>
+
+ </configuration>
+ ]]>
+ </value>
+ </property>
+ </bean>
+
+ <bean name="taskQueueExecutor#repository-scanning"
+ class="org.apache.archiva.components.taskqueue.execution.ThreadedTaskQueueExecutor" lazy-init="false">
+ <property name="name" value="repository-scanning"/>
+ <property name="executor" ref="taskExecutor#repository-scanning"/>
+ <property name="queue" ref="taskQueue#repository-scanning"/>
+ </bean>
+
+ <!--
+ <bean id="repository" class="org.apache.jackrabbit.core.RepositoryImpl" destroy-method="shutdown">
+ <constructor-arg ref="config"/>
+ </bean>
+
+ <bean id="config" class="org.apache.jackrabbit.core.config.RepositoryConfig" factory-method="create">
+ <constructor-arg value="${basedir}/src/test/repository.xml"/>
+ <constructor-arg value="${appserver.base}/jcr"/>
+ </bean>
+ -->
+
+ <bean name="commons-configuration" class="org.apache.archiva.components.registry.commons.CommonsConfigurationRegistry"
+ init-method="initialize">
+ <property name="initialConfiguration">
+ <value>
+ <![CDATA[
+ <configuration>
+ <system/>
+ <properties fileName="${basedir}/src/test/resources/security.properties" config-optional="true"
+ config-at="org.apache.archiva.redback"/>
+ </configuration>
+ ]]>
+ </value>
+ </property>
+ </bean>
+
+
+ <alias name="redbackRuntimeConfigurationAdmin#default" alias="userConfiguration#default"/>
+
+ <alias name="authorizer#rbac" alias="authorizer#default"/>
+
+ <alias name="userManager#configurable" alias="userManager#default"/>
+
+ <!-- ***
+ JPA settings
+ *** -->
+ <bean name="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
+
+ <property name="persistenceXmlLocation" value="classpath:META-INF/persistence-hsqldb.xml" />
+ <property name="jpaPropertyMap">
+ <map>
+ <entry key="openjpa.ConnectionURL" value="jdbc:hsqldb:mem:redback_database" />
+ <entry key="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver" />
+ <entry key="openjpa.ConnectionUserName" value="sa" />
+ <entry key="openjpa.ConnectionPassword" value="" />
+ <entry key="openjpa.Log" value="${openjpa.Log:DefaultLevel=INFO,Runtime=ERROR,Tool=ERROR,SQL=ERROR,Schema=ERROR,MetaData=ERROR}" />
+ <entry key="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)" />
+ <entry key="openjpa.jdbc.MappingDefaults"
+ value="ForeignKeyDeleteAction=restrict,JoinForeignKeyDeleteAction=restrict"/>
+ </map>
+ </property>
+
+ </bean>
+
+ <bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
+ <property name="entityManagerFactory" ref="entityManagerFactory" />
+ </bean>
+
+ <tx:annotation-driven />
+ <!-- ***
+ End of JPA settings
+ *** -->
+</beans>
\ No newline at end of file
<loggers>
<logger name="jaxrs" level="info" />
- <logger name="org.apache.cxf" level="info" />
+ <logger name="org.apache.cxf" level="debug" />
<logger name="org.apache.archiva" level="debug" />
<logger name="org.apache.archiva.redback" level="debug"/>
<logger name="com.fasterxml.jackson" level="info" />
- <logger name="org.apache.archiva.components.registry.commons" level="error" />
+ <logger name="org.apache.archiva.components" level="error" />
<logger name="JPOX" level="error"/>
<logger name="org.apache.archiva.rest.services" level="info"/>
<artifactId>cxf-rt-features-logging</artifactId>
<version>${cxf.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-service-description-openapi-v3</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-core</artifactId>
+ <scope>compile</scope>
+ <version>${io.swagger.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-jaxrs2</artifactId>
+ <version>${io.swagger.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-annotations</artifactId>
+ <version>${io.swagger.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
<dependency>
<groupId>org.apache.archiva</groupId>
<version>${maven.resolver.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.archiva.components</groupId>
+ <artifactId>archiva-components-rest-util</artifactId>
+ <version>${archiva.comp.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.archiva.components</groupId>
<artifactId>archiva-components-expression-evaluator</artifactId>
<version>${archiva.comp.version}</version>
</dependency>
-
<dependency>
<groupId>org.apache.archiva.components</groupId>
<artifactId>archiva-components-spring-taskqueue</artifactId>
</dependency>
+
<!-- Transitive dependency - fixing version -->
<dependency>
<groupId>com.google.guava</groupId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>rest-assured</artifactId>
+ <version>${rest-assured.version}</version>
+ <scope>test</scope>
+ </dependency>
<!-- JUNIT 5 -->
<dependency>
<version>${cxf.version}</version>
</dependency>
- <dependency>
- <groupId>io.swagger.core.v3</groupId>
- <artifactId>swagger-core</artifactId>
- <scope>compile</scope>
- <version>${io.swagger.version}</version>
- <exclusions>
- <exclusion>
- <groupId>javax.ws.rs</groupId>
- <artifactId>jsr311-api</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>io.swagger.core.v3</groupId>
- <artifactId>swagger-jaxrs2</artifactId>
- <version>${io.swagger.version}</version>
- <exclusions>
- <exclusion>
- <groupId>javax.ws.rs</groupId>
- <artifactId>jsr311-api</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>io.swagger.core.v3</groupId>
- <artifactId>swagger-annotations</artifactId>
- <version>${io.swagger.version}</version>
- <exclusions>
- <exclusion>
- <groupId>javax.ws.rs</groupId>
- <artifactId>jsr311-api</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
-
-
-
-
</dependencies>
</dependencyManagement>