From e24e545900b13c66b7c4ec4f585abdfd73c61226 Mon Sep 17 00:00:00 2001 From: Martin Stockhammer Date: Thu, 16 Jul 2020 17:02:04 +0200 Subject: [PATCH] Adding additional REST V2 tests --- .../ldap/role/DefaultLdapRoleMapper.java | 3 +- .../archiva/redback/rest/api/model/Group.java | 7 + .../redback/rest/api/model/PagedResult.java | 5 + .../rest/api/model/PaginationInfo.java | 6 + .../rest/api/services/v2/GroupService.java | 10 +- .../interceptors/JacksonJsonConfigurator.java | 4 + .../rest/services/v2/DefaultGroupService.java | 2 +- .../redback/rest/services/BaseSetup.java | 25 + .../redback/rest/services/LdapInfo.java | 89 +++ .../v2/AbstractNativeRestServices.java | 101 +++- .../v2/AbstractRestServicesTestV2.java | 9 + .../rest/services/v2/GroupServiceTest.java | 4 +- .../v2/NativeAuthenticationServiceTest.java | 7 +- .../services/v2/NativeGroupServiceTest.java | 366 ++++++++++++ .../rest/services/v2/UserServiceTest.java | 528 ++++++++++++++++++ .../resources/META-INF/spring-context.xml | 4 +- 16 files changed, 1140 insertions(+), 30 deletions(-) create mode 100644 redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/LdapInfo.java create mode 100644 redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeGroupServiceTest.java create mode 100644 redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/UserServiceTest.java diff --git a/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/DefaultLdapRoleMapper.java b/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/DefaultLdapRoleMapper.java index e66306d4..afe3d5ee 100644 --- a/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/DefaultLdapRoleMapper.java +++ b/redback-common/redback-common-ldap/src/main/java/org/apache/archiva/redback/common/ldap/role/DefaultLdapRoleMapper.java @@ -239,7 +239,8 @@ public List getAllGroupObjects( DirContext context ) throws MappingEx searchControls.setDerefLinkFlag( true ); searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE ); - searchControls.setReturningAttributes( new String[]{ this.getLdapDnAttribute(), "objectClass", groupNameAttribute} ); + searchControls.setReturningAttributes( new String[]{ this.getLdapDnAttribute(), "objectClass", groupNameAttribute, + ldapGroupMemberAttribute} ); String filter = "objectClass=" + getLdapGroupClass( ); diff --git a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/Group.java b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/Group.java index a4c57937..2b07e320 100644 --- a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/Group.java +++ b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/Group.java @@ -18,6 +18,8 @@ * under the License. */ +import io.swagger.v3.oas.annotations.media.Schema; + import javax.xml.bind.annotation.XmlRootElement; import java.io.Serializable; import java.util.ArrayList; @@ -27,6 +29,7 @@ * @author Martin Stockhammer */ @XmlRootElement(name="group") +@Schema(name="Group", description = "Group object") public class Group implements Serializable { private static final long serialVersionUID = -1842878251787304632L; @@ -44,6 +47,7 @@ public Group( String name ) this.name = name; } + @Schema(description = "The name of the group") public String getName( ) { return name; @@ -54,6 +58,7 @@ public void setName( String name ) this.name = name; } + @Schema(description = "The unique name of the group. Depends on the backend repository, e.g. the LDAP DN.") public String getUniqueName( ) { return uniqueName; @@ -64,6 +69,7 @@ public void setUniqueName( String uniqueName ) this.uniqueName = uniqueName; } + @Schema( description = "The group description, if available" ) public String getDescription( ) { return description; @@ -74,6 +80,7 @@ public void setDescription( String description ) this.description = description; } + @Schema(description = "The list of members. The format of the member strings depends on the backend repository, e.g. for LDAP these may be the member DNs") public List getMemberList( ) { return memberList; diff --git a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/PagedResult.java b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/PagedResult.java index 31681109..cc3d327d 100644 --- a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/PagedResult.java +++ b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/PagedResult.java @@ -18,6 +18,8 @@ * under the License. */ +import io.swagger.v3.oas.annotations.media.Schema; + import javax.xml.bind.annotation.XmlRootElement; import java.util.List; @@ -26,6 +28,7 @@ * @author Martin Stockhammer */ @XmlRootElement(name="pagedResult") +@Schema(name = "PagedResult", description = "Contains paged data. Pages are defined by limit and offset.") public class PagedResult { PaginationInfo pagination; @@ -44,6 +47,7 @@ public static final PagedResult of(long totalSize, long offset, long limi return new PagedResult( totalSize, offset, limit, element); } + @Schema(description = "This is the payload of the paged data. The type of data depends on the REST method. ") public T getData( ) { return data; @@ -54,6 +58,7 @@ public void setData( T data ) this.data = data; } + @Schema(description = "The pagination information") public PaginationInfo getPagination( ) { return pagination; diff --git a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/PaginationInfo.java b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/PaginationInfo.java index 9d5dab5e..4cd0fd87 100644 --- a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/PaginationInfo.java +++ b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/PaginationInfo.java @@ -18,6 +18,8 @@ * under the License. */ +import io.swagger.v3.oas.annotations.media.Schema; + import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @@ -28,6 +30,7 @@ * @author Martin Stockhammer */ @XmlRootElement(name="pagination") +@Schema(name="PaginationInfo", description = "Contains paging information (limit, offset, totalCount)") public class PaginationInfo { long totalCount; @@ -45,6 +48,7 @@ public PaginationInfo( long totalCount, long offset, long limit ) this.limit = limit; } + @Schema(description = "The total number of data available.") public long getTotalCount( ) { return totalCount; @@ -55,6 +59,7 @@ public void setTotalCount( long totalCount ) this.totalCount = totalCount; } + @Schema(description = "The offset of the first element of the returned dataset.") public long getOffset( ) { return offset; @@ -65,6 +70,7 @@ public void setOffset( long offset ) this.offset = offset; } + @Schema(description = "The maximum number of elements returned per page.") public long getLimit( ) { return limit; diff --git a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/services/v2/GroupService.java b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/services/v2/GroupService.java index 6961e5fb..c626085d 100644 --- a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/services/v2/GroupService.java +++ b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/services/v2/GroupService.java @@ -22,6 +22,8 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; import io.swagger.v3.oas.annotations.security.SecurityScheme; import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.archiva.redback.authorization.RedbackAuthorization; @@ -54,9 +56,11 @@ @SecurityScheme( scheme = "BearerAuth", type = SecuritySchemeType.HTTP ) @Tag(name = "v2") @Tag(name = "v2/Groups") +@SecurityRequirement(name = "BearerAuth") public interface GroupService { + public static final String DEFAULT_PAGE_LIMIT = "1000"; @Path( "" ) @GET @@ -67,8 +71,8 @@ public interface GroupService @ApiResponse( description = "List of group objects. The number of returned results depend on the pagination parameters offset and limit." ) } ) - PagedResult> getGroups( @QueryParam( "offset" ) @DefaultValue( "0" ) Integer offset, - @QueryParam( "limit" ) @DefaultValue( value = Integer.MAX_VALUE+"" ) Integer limit) + PagedResult> getGroups( @QueryParam( "offset" ) @DefaultValue( "0" ) Long offset, + @QueryParam( "limit" ) @DefaultValue( value = DEFAULT_PAGE_LIMIT ) Long limit) throws RedbackServiceException; @@ -138,7 +142,7 @@ ActionStatus updateGroupMapping( @Parameter( description = "The group name", req @Consumes( {MediaType.APPLICATION_JSON} ) @Produces( {MediaType.APPLICATION_JSON} ) @RedbackAuthorization( permissions = RedbackRoleConstants.CONFIGURATION_EDIT_OPERATION ) - @Operation( summary = "Updates a multiple group mappings", + @Operation( summary = "Updates multiple group mappings", responses = { @ApiResponse( description = "The status of the update action" ), @ApiResponse( responseCode = "405", description = "Invalid input" ) diff --git a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/JacksonJsonConfigurator.java b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/JacksonJsonConfigurator.java index 4c8eb310..3828c93e 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/JacksonJsonConfigurator.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/JacksonJsonConfigurator.java @@ -18,8 +18,11 @@ * under the License. */ +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.json.JsonWriteFeature; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; @@ -50,6 +53,7 @@ public JacksonJsonConfigurator( @Named("redbackJacksonJsonMapper") ObjectMapper log.info( "configure jackson ObjectMapper" ); objectMapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ); objectMapper.enable( DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL ); + objectMapper.enable( DeserializationFeature.USE_LONG_FOR_INTS ); objectMapper.setAnnotationIntrospector( new JaxbAnnotationIntrospector( objectMapper.getTypeFactory() ) ); objectMapper.findAndRegisterModules( ); objectMapper.registerModule( new JavaTimeModule( ) ); diff --git a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultGroupService.java b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultGroupService.java index 3821416d..93ff99b9 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultGroupService.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultGroupService.java @@ -88,7 +88,7 @@ private static final Group getGroupFromLdap( LdapGroup ldapGroup ) { } @Override - public PagedResult> getGroups( Integer offset, Integer limit ) throws RedbackServiceException + public PagedResult> getGroups( Long offset, Long limit ) throws RedbackServiceException { LdapConnection ldapConnection = null; diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/BaseSetup.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/BaseSetup.java index db9f3bcd..f1df5619 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/BaseSetup.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/BaseSetup.java @@ -29,6 +29,10 @@ public class BaseSetup public static final String SYSPROP_SERVER_PORT = "archiva.rest.server.port"; public static final String SYSPROP_SERVER_BASE_URI = "archiva.rest.server.baseuri"; public static final String SYSPROP_SERVER_ADMIN_PWD = "rest.admin.pwd"; + public static final String SYSPROP_LDAP_URL = "archiva.rest.ldap.url"; + public static final String SYSPROP_LDAP_BASEDN = "archiva.rest.ldap.baseDn"; + public static final String SYSPROP_LDAP_BINDDN = "archiva.rest.ldap.bindDn"; + public static final String SYSPROP_LDAP_BINPWD = "archiva.rest.ldap.bindPwd"; public static String DEFAULT_ADMIN_PWD = "Ackd245aer9sdfan"; @@ -49,4 +53,25 @@ public static String getAdminPwd() { } } + public static boolean startServer() + { + return !"no".equals( System.getProperty( SYSPROP_START_SERVER, "yes" ).toLowerCase( ) ); + } + public static String getServerPort() + { + return System.getProperty( SYSPROP_SERVER_PORT, "" ); + } + + public static String getBaseUri() { + return System.getProperty( SYSPROP_SERVER_BASE_URI, "http://localhost" ); + } + + public static LdapInfo getLdapInfo() { + String url = System.getProperty( SYSPROP_LDAP_URL, "" ); + String baseDn = System.getProperty( SYSPROP_LDAP_BASEDN, "" ); + String bindDn = System.getProperty( SYSPROP_LDAP_BINDDN, "" ); + String bindPwd = System.getProperty( SYSPROP_LDAP_BINPWD, "" ); + + return new LdapInfo( url, baseDn, bindDn, bindPwd ); + } } diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/LdapInfo.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/LdapInfo.java new file mode 100644 index 00000000..ee52fefd --- /dev/null +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/LdapInfo.java @@ -0,0 +1,89 @@ +package org.apache.archiva.redback.rest.services; + +/* + * 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.commons.lang3.StringUtils; + +/** + * @author Martin Stockhammer + */ +public class LdapInfo +{ + String URL; + String baseDN; + String bindDN; + String bindPassword; + boolean remote; + + public LdapInfo( ) + { + } + + public LdapInfo( String URL, String baseDN, String bindDN, String bindPassword ) + { + this.URL = URL; + this.baseDN = baseDN; + this.bindDN = bindDN; + this.bindPassword = bindPassword; + } + + public String getURL( ) + { + return URL; + } + + public void setURL( String URL ) + { + this.URL = URL; + } + + public String getBaseDN( ) + { + return baseDN; + } + + public void setBaseDN( String baseDN ) + { + this.baseDN = baseDN; + } + + public String getBindDN( ) + { + return bindDN; + } + + public void setBindDN( String bindDN ) + { + this.bindDN = bindDN; + } + + public String getBindPassword( ) + { + return bindPassword; + } + + public void setBindPassword( String bindPassword ) + { + this.bindPassword = bindPassword; + } + + public boolean isRemote() { + return StringUtils.isNotEmpty( URL ) && StringUtils.isNotEmpty( baseDN ) && StringUtils.isNotEmpty( bindDN ); + } +} diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/AbstractNativeRestServices.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/AbstractNativeRestServices.java index 1f33566e..54b84ec5 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/AbstractNativeRestServices.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/AbstractNativeRestServices.java @@ -18,8 +18,10 @@ * under the License. */ +import com.fasterxml.jackson.databind.ser.Serializers; import io.restassured.RestAssured; import io.restassured.builder.RequestSpecBuilder; +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; @@ -43,11 +45,13 @@ import org.slf4j.LoggerFactory; import org.springframework.web.context.ContextLoaderListener; +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.baseURI; -import static io.restassured.RestAssured.port; +import static io.restassured.RestAssured.*; +import static io.restassured.http.ContentType.JSON; import static org.apache.archiva.redback.rest.services.BaseSetup.*; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -58,6 +62,7 @@ * @author Martin Stockhammer */ @Tag( "rest-native" ) +@Tag( "rest-v2" ) public abstract class AbstractNativeRestServices { public static final int STOPPED = 0; @@ -65,6 +70,9 @@ public abstract class AbstractNativeRestServices 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( ) ); @@ -75,10 +83,24 @@ public abstract class AbstractNativeRestServices 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( ); @@ -208,7 +230,7 @@ private void setupAdminUser( ) throws UserManagerException, RoleManagerException } else { - um.updateUser( adminUser, false); + um.updateUser( adminUser, false ); } getRoleManager( ).assignRole( "system-administrator", adminUser.getUsername( ) ); } @@ -284,11 +306,7 @@ public void stopServer( ) protected void setupNative( ) throws Exception { - String startServer = System.getProperty( SYSPROP_START_SERVER, "yes" ).toLowerCase( ); - String serverPort = System.getProperty( SYSPROP_SERVER_PORT, "" ); - String baseUri = System.getProperty( SYSPROP_SERVER_BASE_URI, "http://localhost" ); - - if ( !"no".equals( startServer ) ) + if ( this.startServer ) { startServer( ); } @@ -310,24 +328,75 @@ protected void setupNative( ) throws Exception RestAssured.baseURI = "http://localhost"; } String basePath = getBasePath( ); - this.requestSpec = getRequestSpecBuilder().build( ); + this.requestSpec = getRequestSpecBuilder( ).build( ); RestAssured.basePath = basePath; } - protected RequestSpecBuilder getRequestSpecBuilder() { - return new RequestSpecBuilder().setBaseUri( baseURI ) + protected RequestSpecBuilder getRequestSpecBuilder( ) + { + return new RequestSpecBuilder( ).setBaseUri( baseURI ) .setPort( port ) - .setBasePath( getBasePath() ) + .setBasePath( getBasePath( ) ) .addHeader( "Origin", RestAssured.baseURI + ":" + RestAssured.port ); - } - protected RequestSpecification getRequestSpec(String bearerToken) { - return getRequestSpecBuilder( ).addHeader( "Authorization", "Bearer " + bearerToken ).build(); + protected RequestSpecBuilder getAuthRequestSpecBuilder( ) + { + return new RequestSpecBuilder( ).setBaseUri( baseURI ) + .setPort( port ) + .setBasePath( new StringBuilder( ) + .append( getContextRoot( ) ) + .append( getServiceBasePath( ) ).append("/auth").toString() ) + .addHeader( "Origin", RestAssured.baseURI + ":" + RestAssured.port ); + } + + protected RequestSpecification getRequestSpec( String bearerToken ) + { + return getRequestSpecBuilder( ).addHeader( "Authorization", "Bearer " + bearerToken ).build( ); } protected void shutdownNative( ) throws Exception { - stopServer( ); + 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 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 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; } } diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/AbstractRestServicesTestV2.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/AbstractRestServicesTestV2.java index ca8ded4f..ee4f19a0 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/AbstractRestServicesTestV2.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/AbstractRestServicesTestV2.java @@ -46,6 +46,7 @@ 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.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,6 +71,8 @@ */ @ExtendWith( SpringExtension.class ) @ContextConfiguration( locations = { "classpath*:/META-INF/spring-context.xml", "classpath*:/spring-context.xml" } ) +@Tag("rest-local") +@Tag("rest-v2") public abstract class AbstractRestServicesTestV2 { @@ -234,6 +237,12 @@ public static String encode( String uid, String password ) return "Basic " + Base64Utility.encode( ( uid + ":" + password ).getBytes() ); } + public String getUserAuthzHeader(String user) { + assertNotNull( getJwtAuthenticator()); + Token token = getJwtAuthenticator().generateToken( user ); + return "Bearer " + token.getData( ); + } + public String getAdminAuthzHeader() { assertNotNull( getJwtAuthenticator()); diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/GroupServiceTest.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/GroupServiceTest.java index c67f3975..b58f6f1d 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/GroupServiceTest.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/GroupServiceTest.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; @@ -60,6 +61,7 @@ @ContextConfiguration( locations = {"classpath:/ldap-spring-test.xml"} ) @TestInstance( TestInstance.Lifecycle.PER_CLASS ) +@Tag("rest-local") public class GroupServiceTest extends AbstractRestServicesTestV2 { @@ -294,7 +296,7 @@ public void getAllGroups( ) { GroupService service = getGroupService( authorizationHeader ); - List allGroups = service.getGroups( Integer.valueOf( 0 ), Integer.valueOf( Integer.MAX_VALUE ) ).getData( ).stream( ).map( group -> group.getName( ) ).collect( Collectors.toList( ) ); + List allGroups = service.getGroups( Long.valueOf( 0 ), Long.valueOf( Long.MAX_VALUE ) ).getData( ).stream( ).map( group -> group.getName( ) ).collect( Collectors.toList( ) ); assertNotNull( allGroups ); assertEquals( 3, allGroups.size( ) ); diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeAuthenticationServiceTest.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeAuthenticationServiceTest.java index 1022a5ed..2124adee 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeAuthenticationServiceTest.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeAuthenticationServiceTest.java @@ -18,11 +18,7 @@ * under the License. */ -import io.restassured.RestAssured; -import io.restassured.builder.RequestSpecBuilder; import io.restassured.response.Response; -import io.restassured.specification.RequestSpecification; -import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Tag; @@ -37,13 +33,12 @@ import java.util.HashMap; import java.util.Map; -import static io.restassured.RestAssured.*; +import static io.restassured.RestAssured.given; import static io.restassured.http.ContentType.JSON; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.notNullValue; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.springframework.core.annotation.MergedAnnotations.from; /** * @author Martin Stockhammer diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeGroupServiceTest.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeGroupServiceTest.java new file mode 100644 index 00000000..9def33d6 --- /dev/null +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeGroupServiceTest.java @@ -0,0 +1,366 @@ +package org.apache.archiva.redback.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.http.ContentType; +import io.restassured.response.Response; +import org.apache.archiva.components.apacheds.ApacheDs; +import org.apache.archiva.redback.rest.api.model.Group; +import org.apache.archiva.redback.rest.services.BaseSetup; +import org.apache.archiva.redback.rest.services.LdapInfo; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.naming.Context; +import javax.naming.NameNotFoundException; +import javax.naming.NamingException; +import javax.naming.directory.Attributes; +import javax.naming.directory.BasicAttribute; +import javax.naming.directory.BasicAttributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.stream.Collectors; + +import static io.restassured.RestAssured.given; +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Martin Stockhammer + */ +@ExtendWith( SpringExtension.class ) +@ContextConfiguration( + locations = {"classpath:/ldap-spring-test.xml"} ) +@TestInstance( TestInstance.Lifecycle.PER_CLASS ) +@Tag("rest-native") +public class NativeGroupServiceTest extends AbstractNativeRestServices +{ + protected String peopleSuffix; + protected String groupSuffix; + + @Inject + @Named( value = "apacheDS#test" ) + private ApacheDs apacheDs; + + private InitialDirContext adminContext; + private LdapInfo ldapInfo; + + private List groups = + Arrays.asList( "Archiva System Administrator", "Internal Repo Manager", "Internal Repo Observer", "Test Group 1", "Test Group 2", "Test Group 3" ); + + public InitialDirContext getAdminContext() throws NamingException + { + if (this.ldapInfo.isRemote()) { + Hashtable environment = new Hashtable<>( ); + + environment.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapInfo.getURL()); + environment.put(Context.SECURITY_AUTHENTICATION, "simple"); + environment.put(Context.SECURITY_PRINCIPAL, ldapInfo.getBindDN()); + environment.put(Context.SECURITY_CREDENTIALS, ldapInfo.getBindPassword()); + environment.put("com.sun.jndi.ldap.connect.pool", "true"); + return new InitialDirContext(environment); + } else { + return apacheDs.getAdminContext( ); + } + } + + public List getTestGroupList() { + return this.groups; + } + + @Override + protected String getServicePath( ) + { + return "/groups"; + } + + @Override + protected String getSpringConfigLocation( ) + { + return "classpath*:spring-context.xml,classpath*:META-INF/spring-context.xml,classpath:/ldap-spring-test.xml"; + } + + @BeforeAll + void setup( ) throws Exception + { + setupNative( ); + this.ldapInfo = BaseSetup.getLdapInfo( ); + if (!ldapInfo.isRemote()) { + peopleSuffix = "ou=People,dc=archiva,dc=apache,dc=org"; + log.info( "DN Suffix: {}", peopleSuffix ); + if ( apacheDs.isStopped( ) ) + { + groupSuffix = apacheDs.addSimplePartition( "test", new String[]{"archiva", "apache", "org"} ).getSuffix( ); + + log.info( "groupSuffix: {}", groupSuffix ); + apacheDs.startServer( ); + if ( !exists( apacheDs.getAdminContext( ), peopleSuffix ) ) + { + BasicAttribute objectClass = new BasicAttribute( "objectClass" ); + objectClass.add( "top" ); + objectClass.add( "organizationalUnit" ); + + Attributes attributes = new BasicAttributes( true ); + attributes.put( objectClass ); + attributes.put( "organizationalUnitName", "foo" ); + + apacheDs.getAdminContext( ).createSubcontext( peopleSuffix, attributes ); + } + } + } else { + this.peopleSuffix = "ou=People," + ldapInfo.getBaseDN( ); + this.groupSuffix = ldapInfo.getBaseDN( ); + } + } + + @AfterAll + void shutdown( ) throws Exception + { + shutdownNative(); + if (!this.ldapInfo.isRemote()) + { + + try + { + InitialDirContext context = null; + try + { + context = getAdminContext( ); + context.unbind( this.peopleSuffix ); + } + finally + { + try + { + if ( context != null ) context.close( ); + } + catch ( Exception e ) + { + log.error( "Error during context close {}", e.getMessage( ) ); + } + try + { + apacheDs.stopServer( ); + } + catch ( Exception e ) + { + log.error( "Could not stop apacheds {}", e.getMessage( ) ); + } + } + } + catch ( Exception e ) + { + log.error( "Could not stop ldap {}", e.getMessage( ) ); + } + } + getAdminContext().close(); + } + + @BeforeEach + public void initLdap( ) throws Exception + { + removeAllGroups( ); + createGroups( ); + } + + @AfterEach + public void cleanupLdap( ) throws NamingException + { + removeAllGroups( ); + } + + protected boolean exists( DirContext context, String dn ) + { + Object result = null; + try { + result = context.lookup( dn ); + } + catch ( NameNotFoundException e ) { + return false; + } + catch ( NamingException e ) + { + log.error( "Unknown error during lookup: {}", e.getMessage( ) ); + } + return result != null; + } + + private void removeAllGroups( ) + { + InitialDirContext context = null; + try + { + context = getAdminContext( ); + for ( String group : getTestGroupList() ) + { + try + { + context.unbind( createGroupDn( group ) ); + } + catch ( NamingException e ) + { + // Ignore + } + } + + } + catch ( NamingException e ) + { + log.error( "Naming exception {}", e.getMessage( ) ); + } + finally + { + try + { + if ( context != null ) context.close( ); + } + catch ( Exception e ) + { + log.error( "Error during context close {}", e.getMessage( ) ); + } + } + } + + private String createGroupDn( String cn ) + { + return "cn=" + cn + "," + groupSuffix; + } + + private void createGroup( DirContext context, String groupName, String dn ) + throws Exception + { + if ( !exists( context, dn ) ) + { + Attributes attributes = new BasicAttributes( true ); + BasicAttribute objectClass = new BasicAttribute( "objectClass" ); + objectClass.add( "top" ); + objectClass.add( "groupOfUniqueNames" ); + attributes.put( objectClass ); + attributes.put( "cn", groupName ); + BasicAttribute basicAttribute = new BasicAttribute( "uniquemember" ); + + basicAttribute.add( "uid=admin," + peopleSuffix ); + + attributes.put( basicAttribute ); + + context.createSubcontext( dn, attributes ); + } + else + { + log.error( "Group {} exists already", dn ); + } + } + + private void createGroups( ) + throws Exception + { + InitialDirContext context = null; + try + { + context = getAdminContext( ); + + for ( String group : getTestGroupList() ) + { + createGroup( context, group, createGroupDn( group ) ); + } + } + finally + { + if ( context != null ) + { + context.close( ); + } + } + } + + + @Test + void getGroups() { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( ContentType.JSON ).when( ) + .get( ).then( ).statusCode( 200 ).extract( ).response( ); + assertNotNull( response ); + List data = response.body( ).jsonPath( ).getList( "data", Group.class ); + assertNotNull( data ); + assertEquals( Integer.valueOf( 0 ), response.body( ).jsonPath( ).get( "pagination.offset" ) ); + assertEquals( Integer.valueOf( 1000 ), response.body( ).jsonPath( ).get( "pagination.limit" ) ); + assertEquals( Integer.valueOf( 6 ), response.body( ).jsonPath( ).get( "pagination.totalCount" ) ); + assertEquals( 6, data.size( ) ); + String[] values = data.stream( ).map( ldapInfo -> ldapInfo.getName( ) ).sorted( ).collect( Collectors.toList( ) ).toArray( new String[0] ); + assertArrayEquals( getTestGroupList( ).toArray( new String[0] ), values ); + assertEquals( "uid=admin," + this.peopleSuffix, data.get( 0 ).getMemberList( ).get( 0 ) ); + } + + @Test + void getGroupsWithLimit() { + String token = getAdminToken( ); + HashMap params = new HashMap<>( ); + params.put( "limit", Long.valueOf( 3 ) ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( ContentType.JSON ) + .param( "limit", Long.valueOf( 3 ) ) + .when( ) + .get( ).then( ).statusCode( 200 ).extract( ).response( ); + assertNotNull( response ); + List data = response.body( ).jsonPath( ).getList( "data", Group.class ); + assertNotNull( data ); + assertEquals( Integer.valueOf( 0 ), response.body( ).jsonPath( ).get( "pagination.offset" ) ); + assertEquals( Integer.valueOf( 3 ), response.body( ).jsonPath( ).get( "pagination.limit" ) ); + assertEquals( Integer.valueOf( 6 ), response.body( ).jsonPath( ).get( "pagination.totalCount" ) ); + assertEquals( 3, data.size( ) ); + String[] values = data.stream( ).map( ldapInfo -> ldapInfo.getName( ) ).sorted( ).collect( Collectors.toList( ) ).toArray( new String[0] ); + assertArrayEquals( getTestGroupList( ).subList( 0, 3 ).toArray( new String[0] ), values ); + assertEquals( "uid=admin," + this.peopleSuffix, data.get( 0 ).getMemberList( ).get( 0 ) ); + } + + @Test + void getGroupsWithOffset() { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( ContentType.JSON ) + .param( "offset", Long.valueOf( 2 ) ) + .when( ) + .get( ).then( ).statusCode( 200 ).extract( ).response( ); + System.out.println( response.print( ) ); + assertNotNull( response ); + List data = response.body( ).jsonPath( ).getList( "data", Group.class ); + assertNotNull( data ); + assertEquals( Integer.valueOf( 2 ), response.body( ).jsonPath( ).get( "pagination.offset" ) ); + assertEquals( Integer.valueOf( 1000 ), response.body( ).jsonPath( ).get( "pagination.limit" ) ); + assertEquals( Integer.valueOf( 6 ), response.body( ).jsonPath( ).get( "pagination.totalCount" ) ); + assertEquals( 4, data.size( ) ); + String[] values = data.stream( ).map( ldapInfo -> ldapInfo.getName( ) ).sorted( ).collect( Collectors.toList( ) ).toArray( new String[0] ); + assertArrayEquals( getTestGroupList( ).subList( 2, getTestGroupList().size() ).toArray( new String[0] ), values ); + assertEquals( "uid=admin," + this.peopleSuffix, data.get( 0 ).getMemberList( ).get( 0 ) ); + } + + +} diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/UserServiceTest.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/UserServiceTest.java new file mode 100644 index 00000000..9c342e78 --- /dev/null +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/UserServiceTest.java @@ -0,0 +1,528 @@ +package org.apache.archiva.redback.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.jaxrs.json.JacksonJaxbJsonProvider; +import org.apache.archiva.redback.rest.api.model.Operation; +import org.apache.archiva.redback.rest.api.model.Permission; +import org.apache.archiva.redback.rest.api.model.RequestTokenRequest; +import org.apache.archiva.redback.rest.api.model.ResetPasswordRequest; +import org.apache.archiva.redback.rest.api.model.TokenResponse; +import org.apache.archiva.redback.rest.api.model.User; +import org.apache.archiva.redback.rest.api.model.UserRegistrationRequest; +import org.apache.archiva.redback.rest.api.services.UserService; +import org.apache.archiva.redback.rest.services.FakeCreateAdminService; +import org.apache.archiva.redback.rest.services.mock.EmailMessage; +import org.apache.archiva.redback.rest.services.mock.MockJavaMailSender; +import org.apache.archiva.redback.rest.services.mock.ServicesAssert; +import org.apache.cxf.jaxrs.client.JAXRSClientFactory; +import org.apache.cxf.jaxrs.client.WebClient; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import javax.inject.Inject; +import javax.ws.rs.ForbiddenException; +import javax.ws.rs.core.MediaType; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + + +/** + * @author Olivier Lamy + */ +@ExtendWith( SpringExtension.class ) +@ContextConfiguration( + locations = {"classpath:/spring-context.xml"} ) +@TestInstance( TestInstance.Lifecycle.PER_CLASS ) +public class UserServiceTest + extends AbstractRestServicesTestV2 +{ + + @Inject + MockJavaMailSender mockJavaMailSender; + + @AfterEach + void cleanup() { + mockJavaMailSender.getSendedEmails( ).clear( ); + } + + @BeforeAll + void setup( ) throws Exception + { + super.init( ); + super.startServer( ); + } + + @AfterAll + void shutdown( ) throws Exception + { + super.stopServer( ); + super.destroy( ); + } + + private UserService getUserService( String authzHeader ) + { + UserService service = + JAXRSClientFactory.create( "http://localhost:" + getServerPort( ) + "/" + getRestServicesPath( ) + "/v2/redback/", + UserService.class, Collections.singletonList( new JacksonJaxbJsonProvider( ) ) ); + + // time out for debuging purpose + WebClient.getConfig( service ).getHttpConduit( ).getClient( ).setReceiveTimeout( getTimeout( ) ); + + if ( authzHeader != null ) + { + WebClient.client( service ).header( "Authorization", authzHeader ); + } + WebClient.client( service ).header( "Referer", "http://localhost:" + getServerPort( ) ); + WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE ); + WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE ); + + return service; + } + + @Test + public void ping( ) + throws Exception + { + Boolean res = getUserService( null ).ping( ); + assertTrue( res ); + } + + @Test + public void getUsers( ) + throws Exception + { + String adminHeader = getAdminAuthzHeader( ); + UserService userService = getUserService( adminHeader ); + List users = userService.getUsers( ); + assertNotNull( users ); + assertFalse( users.isEmpty( ) ); + } + + @Test() + @Disabled + public void getUsersWithoutAuthz( ) + throws Exception + { + UserService userService = getUserService( null ); + assertThrows( ForbiddenException.class, ( ) -> { + try + { + userService.getUsers( ); + } + catch ( ForbiddenException e ) + { + assertEquals( 403, e.getResponse( ).getStatus( ) ); + throw e; + } + } ); + + + } + + @Test + public void getNoPermissionNotAuthz( ) + { + + UserService userService = getUserService( null ); + WebClient.client( userService ).header( "Origin", "http://localhost/myrequest" ); + + try + { + getFakeCreateAdminService( ).testAuthzWithoutKarmasNeededButAuthz( ); + } + catch ( ForbiddenException e ) + { + assertEquals( 403, e.getResponse( ).getStatus( ) ); + throw e; + } + } + + @Test + public void getNoPermissionAuthz( ) + { + + try + { + FakeCreateAdminService service = getFakeCreateAdminService( ); + + WebClient.client( service ).header( "Authorization", getAdminAuthzHeader( ) ); + + assertTrue( service.testAuthzWithoutKarmasNeededButAuthz( ) ); + + } + catch ( ForbiddenException e ) + { + assertEquals( 403, e.getResponse( ).getStatus( ) ); + throw e; + } + } + + @Test + @Disabled + public void register( ) + throws Exception + { + try + { + mockJavaMailSender.getSendedEmails( ).clear( ); + UserService service = getUserService( getAdminAuthzHeader( ) ); + User u = new User( ); + u.setFullName( "the toto" ); + u.setUsername( "toto" ); + u.setEmail( "toto@toto.fr" ); + u.setPassword( "toto123" ); + u.setConfirmPassword( "toto123" ); + String key = service.registerUser( new UserRegistrationRequest( u, "http://wine.fr/bordeaux" ) ).getKey( ); + + assertNotEquals( "-1", key ); + + ServicesAssert assertService = + JAXRSClientFactory.create( "http://localhost:" + getServerPort( ) + "/" + getRestServicesPath( ) + "/testsService/", + ServicesAssert.class, + Collections.singletonList( new JacksonJaxbJsonProvider( ) ) ); + + List emailMessages = assertService.getEmailMessageSended( ); + assertEquals( 1, emailMessages.size( ) ); + assertEquals( "toto@toto.fr", emailMessages.get( 0 ).getTos( ).get( 0 ) ); + + assertEquals( "Welcome", emailMessages.get( 0 ).getSubject( ) ); + String messageContent = emailMessages.get( 0 ).getText( ); + + log.info( "messageContent: {}", messageContent ); + + assertNotNull( messageContent ); + assertTrue( messageContent.contains( "Use the following URL to validate your account." ) ); + assertTrue( messageContent.contains( "http://wine.fr/bordeaux" ) ); + assertTrue( messageContent.contains( "toto" ) ); + + assertTrue( service.validateUserFromKey( key ).isSuccess( ) ); + + service = getUserService( getAdminAuthzHeader( ) ); + + u = service.getUser( "toto" ); + + assertNotNull( u ); + assertTrue( u.isValidated( ) ); + assertTrue( u.isPasswordChangeRequired( ) ); + + assertTrue( service.validateUserFromKey( key ).isSuccess( ) ); + + } + catch ( Exception e ) + { + log.error( e.getMessage( ), e ); + throw e; + } + finally + { + deleteUserQuietly( "toto" ); + } + + } + + @Test + public void registerNoUrl( ) + throws Exception + { + try + { + UserService service = getUserService( getAdminAuthzHeader( ) ); + User u = new User( ); + u.setFullName( "the toto" ); + u.setUsername( "toto" ); + u.setEmail( "toto@toto.fr" ); + u.setPassword( "toto123" ); + u.setConfirmPassword( "toto123" ); + String key = service.registerUser( new UserRegistrationRequest( u, null ) ).getKey( ); + + assertNotEquals( "-1", key ); + + ServicesAssert assertService = + JAXRSClientFactory.create( "http://localhost:" + getServerPort( ) + "/" + getRestServicesPath( ) + "/testsService/", + ServicesAssert.class, + Collections.singletonList( new JacksonJaxbJsonProvider( ) ) ); + + List emailMessages = assertService.getEmailMessageSended( ); + assertEquals( 1, emailMessages.size( ) ); + assertEquals( "toto@toto.fr", emailMessages.get( 0 ).getTos( ).get( 0 ) ); + + assertEquals( "Welcome", emailMessages.get( 0 ).getSubject( ) ); + String messageContent = emailMessages.get( 0 ).getText( ); + + log.info( "messageContent: {}", messageContent ); + assertNotNull( messageContent ); + assertTrue( messageContent.contains( "Use the following URL to validate your account." ) ); + assertTrue( messageContent.contains( "http://localhost:" + getServerPort( ) ) ); + assertTrue( messageContent.toLowerCase( ).contains( "toto" ) ); + + assertTrue( service.validateUserFromKey( key ).isSuccess( ) ); + + service = getUserService( getAdminAuthzHeader( ) ); + + u = service.getUser( "toto" ); + + assertNotNull( u ); + assertTrue( u.isValidated( ) ); + assertTrue( u.isPasswordChangeRequired( ) ); + + assertTrue( service.validateUserFromKey( key ).isSuccess( ) ); + + } + catch ( Exception e ) + { + log.error( e.getMessage( ), e ); + throw e; + } + finally + { + deleteUserQuietly( "toto" ); + } + + } + + @Test + @Disabled + public void resetPassword( ) + throws Exception + { + try + { + mockJavaMailSender.getSendedEmails().clear(); + + UserService service = getUserService( getAdminAuthzHeader( ) ); + User u = new User( ); + u.setFullName( "the toto" ); + u.setUsername( "toto" ); + u.setEmail( "toto@toto.fr" ); + u.setPassword( "toto123" ); + u.setConfirmPassword( "toto123" ); + String key = service.registerUser( new UserRegistrationRequest( u, "http://wine.fr/bordeaux" ) ).getKey( ); + + assertNotEquals( "-1", key ); + + ServicesAssert assertService = + JAXRSClientFactory.create( "http://localhost:" + getServerPort( ) + "/" + getRestServicesPath( ) + "/testsService/", + ServicesAssert.class, + Collections.singletonList( new JacksonJaxbJsonProvider( ) ) ); + + WebClient.client( assertService ).accept( MediaType.APPLICATION_JSON_TYPE ); + WebClient.client( assertService ).type( MediaType.APPLICATION_JSON_TYPE ); + + List emailMessages = assertService.getEmailMessageSended( ); + assertEquals( 1, emailMessages.size( ) ); + assertEquals( "toto@toto.fr", emailMessages.get( 0 ).getTos( ).get( 0 ) ); + + assertEquals( "Welcome", emailMessages.get( 0 ).getSubject( ) ); + assertTrue( + emailMessages.get( 0 ).getText( ).contains( "Use the following URL to validate your account." ) ); + + assertTrue( service.validateUserFromKey( key ).isSuccess( ) ); + + service = getUserService( getAdminAuthzHeader( ) ); + + u = service.getUser( "toto" ); + + assertNotNull( u ); + assertTrue( u.isValidated( ) ); + assertTrue( u.isPasswordChangeRequired( ) ); + + assertTrue( service.validateUserFromKey( key ).isSuccess( ) ); + + assertTrue( service.resetPassword( new ResetPasswordRequest( "toto", "http://foo.fr/bar" ) ).isSuccess( ) ); + + emailMessages = assertService.getEmailMessageSended( ); + assertEquals( 2, emailMessages.size( ) ); + assertEquals( "toto@toto.fr", emailMessages.get( 1 ).getTos( ).get( 0 ) ); + + String messageContent = emailMessages.get( 1 ).getText( ); + + assertNotNull( messageContent ); + assertTrue( messageContent.contains( "Password Reset" ) ); + assertTrue( messageContent.contains( "Username: toto" ) ); + assertTrue( messageContent.contains( "http://foo.fr/bar" ) ); + + + } + catch ( Exception e ) + { + log.error( e.getMessage( ), e ); + throw e; + } + finally + { + deleteUserQuietly( "toto" ); + } + + } + + private void deleteUserQuietly( String userName ) + { + try + { + getUserService( getAdminAuthzHeader( ) ).deleteUser( userName ); + } + catch ( Exception e ) + { + log.warn( "ignore fail to delete user " + e.getMessage( ), e ); + } + } + + @Test + public void getAdminPermissions( ) + throws Exception + { + Collection permissions = getUserService( getAdminAuthzHeader( ) ).getUserPermissions( "admin" ); + log.info( "admin permisssions: {}", permissions ); + } + + @Test + public void getGuestPermissions( ) + throws Exception + { + createGuestIfNeeded( ); + Collection permissions = getUserService( null ).getCurrentUserPermissions( ); + log.info( "guest permisssions: {}", permissions ); + } + + @Test + public void getAdminOperations( ) + throws Exception + { + Collection operations = getUserService( getAdminAuthzHeader( ) ).getUserOperations( "admin" ); + log.info( "admin operations: {}", operations ); + } + + @Test + public void getGuestOperations( ) + throws Exception + { + createGuestIfNeeded( ); + Collection operations = getUserService( null ).getCurrentUserOperations( ); + log.info( "guest operations: {}", operations ); + } + + @Test + public void updateMe( ) + throws Exception + { + User u = new User( ); + u.setFullName( "the toto" ); + u.setUsername( "toto" ); + u.setEmail( "toto@toto.fr" ); + u.setPassword( "toto123" ); + u.setConfirmPassword( "toto123" ); + u.setValidated( true ); + getUserService( getAdminAuthzHeader( ) ).createUser( u ); + + u.setFullName( "the toto123" ); + u.setEmail( "toto@titi.fr" ); + u.setPassword( "toto1234" ); + u.setPreviousPassword( "toto123" ); + getUserService( getUserAuthzHeader( "toto" ) ).updateMe( u ); + + u = getUserService( getAdminAuthzHeader( ) ).getUser( "toto" ); + assertEquals( "the toto123", u.getFullName( ) ); + assertEquals( "toto@titi.fr", u.getEmail( ) ); + + u.setFullName( "the toto1234" ); + u.setEmail( "toto@tititi.fr" ); + u.setPassword( "toto12345" ); + u.setPreviousPassword( "toto1234" ); + getUserService( getUserAuthzHeader( "toto" )) .updateMe( u ); + + u = getUserService( getAdminAuthzHeader( ) ).getUser( "toto" ); + assertEquals( "the toto1234", u.getFullName( ) ); + assertEquals( "toto@tititi.fr", u.getEmail( ) ); + + getUserService( getAdminAuthzHeader( ) ).deleteUser( "toto" ); + } + + @Test + @Disabled + public void lockUnlockUser( ) + throws Exception + { + try + { + + // START SNIPPET: create-user + User user = new User( "toto", "toto the king", "toto@toto.fr", false, false ); + user.setPassword( "foo123" ); + user.setPermanent( false ); + user.setPasswordChangeRequired( false ); + user.setLocked( false ); + user.setValidated( true ); + UserService userService = getUserService( getAdminAuthzHeader( ) ); + userService.createUser( user ); + // END SNIPPET: create-user + user = userService.getUser( "toto" ); + assertNotNull( user ); + assertEquals( "toto the king", user.getFullName( ) ); + assertEquals( "toto@toto.fr", user.getEmail( ) ); + TokenResponse result = getLoginServiceV2( null ).logIn( new RequestTokenRequest( "toto", "foo123" ) ); + getLoginServiceV2( "Bearer " + result.getAccessToken( ) ).pingWithAutz( ); + + userService.lockUser( "toto" ); + + assertTrue( userService.getUser( "toto" ).isLocked( ) ); + + userService.unlockUser( "toto" ); + + assertFalse( userService.getUser( "toto" ).isLocked( ) ); + } + finally + { + getUserService( getAdminAuthzHeader( ) ).deleteUser( "toto" ); + getUserService( getAdminAuthzHeader( ) ).removeFromCache( "toto" ); + assertNull( getUserService( getAdminAuthzHeader( ) ).getUser( "toto" ) ); + } + } + + public void guestUserCreate( ) + throws Exception + { + UserService userService = getUserService( getAdminAuthzHeader( ) ); + assertNull( userService.getGuestUser( ) ); + assertNull( userService.createGuestUser( ) ); + + } + + protected void createGuestIfNeeded( ) + throws Exception + { + UserService userService = getUserService( getAdminAuthzHeader( ) ); + if ( userService.getGuestUser( ) == null ) + { + userService.createGuestUser( ); + } + } + +} diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/resources/META-INF/spring-context.xml b/redback-integrations/redback-rest/redback-rest-services/src/test/resources/META-INF/spring-context.xml index 13ce4791..33a4410a 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/test/resources/META-INF/spring-context.xml +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/resources/META-INF/spring-context.xml @@ -32,7 +32,7 @@ --> - + @@ -42,7 +42,7 @@ - +