<properties> | <properties> | ||||
<enunciate.docsDir>${project.build.outputDirectory}/rest-docs-archiva-rest-api</enunciate.docsDir> | <enunciate.docsDir>${project.build.outputDirectory}/rest-docs-archiva-rest-api</enunciate.docsDir> | ||||
<site.staging.base>${project.parent.parent.parent.basedir}</site.staging.base> | <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> | </properties> | ||||
<dependencies> | <dependencies> | ||||
</exclusion> | </exclusion> | ||||
</exclusions> | </exclusions> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.apache.archiva.components</groupId> | |||||
<artifactId>archiva-components-rest-util</artifactId> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>jakarta.ws.rs</groupId> | <groupId>jakarta.ws.rs</groupId> | ||||
<artifactId>jakarta.ws.rs-api</artifactId> | <artifactId>jakarta.ws.rs-api</artifactId> | ||||
<artifactId>jakarta.annotation-api</artifactId> | <artifactId>jakarta.annotation-api</artifactId> | ||||
</dependency> | </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> | </dependencies> | ||||
<build> | <build> |
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; | |||||
} | |||||
} |
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(); | |||||
} | |||||
} |
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( ); | |||||
} | |||||
} |
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( ); | |||||
} | |||||
} |
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 ); | |||||
} | |||||
} |
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 ); | |||||
} | |||||
} |
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"; | |||||
} |
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. | * 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. | * Service for configuration of redback and security related settings. | ||||
* @author Martin Stockhammer <martin_s@apache.org> | * @author Martin Stockhammer <martin_s@apache.org> | ||||
* @since 3.0 | * @since 3.0 | ||||
*/ | */ | ||||
@Path( "/security" ) | |||||
@Tag(name = "v2") | |||||
@Tag(name = "v2/Security") | |||||
@SecurityRequirement(name = "BearerAuth") | |||||
public interface SecurityConfigurationService | 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> | <groupId>org.apache.cxf</groupId> | ||||
<artifactId>cxf-rt-features-logging</artifactId> | <artifactId>cxf-rt-features-logging</artifactId> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.apache.cxf</groupId> | |||||
<artifactId>cxf-rt-rs-extension-providers</artifactId> | |||||
<scope>runtime</scope> | |||||
</dependency> | |||||
<!-- TEST Scope --> | <!-- TEST Scope --> | ||||
<dependency> | <dependency> | ||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>io.rest-assured</groupId> | |||||
<artifactId>rest-assured</artifactId> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<!-- Needed for JDK >= 9 --> | <!-- Needed for JDK >= 9 --> | ||||
<dependency> | <dependency> |
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(); | |||||
} | |||||
} |
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; | |||||
} | |||||
} |
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 | <context:component-scan | ||||
base-package="org.apache.archiva.rest.services,org.apache.archiva.redback.rest.services"/> | 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"> | <bean id="jsonProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider"> | ||||
<property name="mapper" ref="redbackJacksonJsonMapper"/> | <property name="mapper" ref="redbackJacksonJsonMapper"/> | ||||
</bean> | </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"> | <bean id="xmlProvider" class="com.fasterxml.jackson.jaxrs.xml.JacksonJaxbXMLProvider"> | ||||
<property name="mapper" ref="redbackJacksonXMLMapper"/> | <property name="mapper" ref="redbackJacksonXMLMapper"/> | ||||
</bean> | </bean> | ||||
<bean id="redbackJacksonJsonMapper" class="com.fasterxml.jackson.databind.ObjectMapper" /> | <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" /> | <bean id="redbackJacksonXMLMapper" class="com.fasterxml.jackson.dataformat.xml.XmlMapper" /> | ||||
</jaxrs:server> | </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" | <bean name="browse#versionMetadata" class="org.apache.archiva.components.cache.ehcache.EhcacheCache" | ||||
init-method="initialize"> | init-method="initialize"> | ||||
<property name="diskPersistent" value="false"/> | <property name="diskPersistent" value="false"/> |
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; | |||||
} | |||||
} |
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" ) ); | |||||
} | |||||
} |
<?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> |
<loggers> | <loggers> | ||||
<logger name="jaxrs" level="info" /> | <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" level="debug" /> | ||||
<logger name="org.apache.archiva.redback" level="debug"/> | <logger name="org.apache.archiva.redback" level="debug"/> | ||||
<logger name="com.fasterxml.jackson" level="info" /> | <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="JPOX" level="error"/> | ||||
<logger name="org.apache.archiva.rest.services" level="info"/> | <logger name="org.apache.archiva.rest.services" level="info"/> |
<artifactId>cxf-rt-features-logging</artifactId> | <artifactId>cxf-rt-features-logging</artifactId> | ||||
<version>${cxf.version}</version> | <version>${cxf.version}</version> | ||||
</dependency> | </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> | <dependency> | ||||
<groupId>org.apache.archiva</groupId> | <groupId>org.apache.archiva</groupId> | ||||
<version>${maven.resolver.version}</version> | <version>${maven.resolver.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.apache.archiva.components</groupId> | |||||
<artifactId>archiva-components-rest-util</artifactId> | |||||
<version>${archiva.comp.version}</version> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>org.apache.archiva.components</groupId> | <groupId>org.apache.archiva.components</groupId> | ||||
<artifactId>archiva-components-expression-evaluator</artifactId> | <artifactId>archiva-components-expression-evaluator</artifactId> | ||||
<version>${archiva.comp.version}</version> | <version>${archiva.comp.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
<groupId>org.apache.archiva.components</groupId> | <groupId>org.apache.archiva.components</groupId> | ||||
<artifactId>archiva-components-spring-taskqueue</artifactId> | <artifactId>archiva-components-spring-taskqueue</artifactId> | ||||
</dependency> | </dependency> | ||||
<!-- Transitive dependency - fixing version --> | <!-- Transitive dependency - fixing version --> | ||||
<dependency> | <dependency> | ||||
<groupId>com.google.guava</groupId> | <groupId>com.google.guava</groupId> | ||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>io.rest-assured</groupId> | |||||
<artifactId>rest-assured</artifactId> | |||||
<version>${rest-assured.version}</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<!-- JUNIT 5 --> | <!-- JUNIT 5 --> | ||||
<dependency> | <dependency> | ||||
<version>${cxf.version}</version> | <version>${cxf.version}</version> | ||||
</dependency> | </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> | </dependencies> | ||||
</dependencyManagement> | </dependencyManagement> | ||||