This is an automated email from the ASF dual-hosted git repository. martin_s pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/archiva-redback-core.git
commit 8242f07b084ede25c768afb14f4c647ddacf5563 Author: Martin Stockhammer <[email protected]> AuthorDate: Sun Jul 26 21:10:44 2020 +0200 Improving V2 REST services --- .../apache/archiva/redback/rest/api/Constants.java | 28 ++- .../redback/rest/api/model/ErrorMessage.java | 4 + .../services/v2/DefaultAuthenticationService.java | 35 ++-- .../rest/services/v2/DefaultGroupService.java | 24 ++- .../rest/services/v2/DefaultUserService.java | 33 ++-- .../services/v2/AbstractNativeRestServices.java | 14 ++ .../rest/services/v2/NativeUserServiceTest.java | 197 +++++++++++++++++++-- 7 files changed, 277 insertions(+), 58 deletions(-) diff --git a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/Constants.java b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/Constants.java index cd72bf5..cc20152 100644 --- a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/Constants.java +++ b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/Constants.java @@ -21,7 +21,31 @@ package org.apache.archiva.redback.rest.api; /** * @author Martin Stockhammer <[email protected]> */ -public class Constants +public interface Constants { - public static final String DEFAULT_PAGE_LIMIT = "1000"; + String DEFAULT_PAGE_LIMIT = "1000"; + + String ERR_UNKNOWN = "redback:unknown_error"; + String ERR_USER_EXISTS = "redback:user.exists"; + String ERR_USER_ID_EMPTY = "redback:user.id.empty"; + String ERR_USER_FULL_NAME_EMPTY = "redback:user.fullname.empty"; + String ERR_USER_EMAIL_EMPTY = "redback:user.email.empty"; + String ERR_USER_ASSIGN_ROLE = "redback:user.role.assign.failure"; + String ERR_USER_NOT_VALIDATED = "redback:user.not_validated"; + + String ERR_LDAP_GENERIC = "redback:ldap.error"; + String ERR_ROLE_MAPPING = "redback:role.mapping.error"; + String ERR_ROLE_MAPPING_NOT_FOUND = "redback:role.mapping.not_found"; + + String ERR_AUTH_BAD_CODE = "redback:auth.bad_authorization_code"; + String ERR_AUTH_INVALID_CREDENTIALS = "redback:auth.invalid_credentials"; + String ERR_AUTH_FAIL_MSG = "redback:auth.fail"; + String ERR_AUTH_ACCOUNT_LOCKED = "redback:auth.account_locked"; + String ERR_AUTH_PASSWORD_CHANGE_REQUIRED = "redback:auth.password_change_required"; + String ERR_AUTH_USERMANAGER_FAIL = "redback:auth.usermanager_error"; + String ERR_AUTH_UNSUPPORTED_GRANT_TYPE = "redback:auth.unsupported_grant"; + String ERR_AUTH_INVALID_TOKEN = "redback:auth.invalid_token"; + String ERR_AUTH_UNAUTHORIZED_REQUEST = "redback:auth.unauthorized_request"; + + } diff --git a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/ErrorMessage.java b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/ErrorMessage.java index d47e746..0615639 100644 --- a/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/ErrorMessage.java +++ b/redback-integrations/redback-rest/redback-rest-api/src/main/java/org/apache/archiva/redback/rest/api/model/ErrorMessage.java @@ -57,6 +57,10 @@ public class ErrorMessage this.args = args; } + public static ErrorMessage of(String errorKey, String... args) { + return new ErrorMessage( errorKey, args ); + } + public String getErrorKey() { return errorKey; diff --git a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultAuthenticationService.java b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultAuthenticationService.java index 2c62703..1272b97 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultAuthenticationService.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultAuthenticationService.java @@ -31,11 +31,11 @@ import org.apache.archiva.redback.policy.AccountLockedException; import org.apache.archiva.redback.policy.MustChangePasswordException; import org.apache.archiva.redback.rest.api.model.ErrorMessage; import org.apache.archiva.redback.rest.api.model.GrantType; -import org.apache.archiva.redback.rest.api.model.v2.PingResult; -import org.apache.archiva.redback.rest.api.model.v2.TokenRequest; 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.UserLogin; +import org.apache.archiva.redback.rest.api.model.v2.PingResult; +import org.apache.archiva.redback.rest.api.model.v2.TokenRequest; import org.apache.archiva.redback.rest.api.services.RedbackServiceException; import org.apache.archiva.redback.rest.api.services.v2.AuthenticationService; import org.apache.archiva.redback.rest.services.interceptors.RedbackPrincipal; @@ -56,9 +56,10 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import java.security.Principal; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import static org.apache.archiva.redback.rest.api.Constants.*; + /** * * Authentication service provides REST methods for authentication and verification. @@ -127,7 +128,7 @@ public class DefaultAuthenticationService throws RedbackServiceException { if (!GrantType.AUTHORIZATION_CODE.equals(loginRequest.getGrantType())) { - throw new RedbackServiceException( "redback:bad_authorization_code", Response.Status.FORBIDDEN.getStatusCode( ) ); + throw new RedbackServiceException( ErrorMessage.of( ERR_AUTH_BAD_CODE ), Response.Status.FORBIDDEN.getStatusCode( ) ); } String userName = loginRequest.getUserId(), password = loginRequest.getPassword(); PasswordBasedAuthenticationDataSource authDataSource = @@ -146,7 +147,7 @@ public class DefaultAuthenticationService if ( !user.isValidated() ) { log.info( "user {} not validated", user.getUsername() ); - throw new RedbackServiceException( "redback:user-not-validated", Response.Status.FORBIDDEN.getStatusCode() ); + throw new RedbackServiceException( ErrorMessage.of( ERR_USER_NOT_VALIDATED, user.getUsername() ), Response.Status.FORBIDDEN.getStatusCode() ); } // Stateless services no session // httpAuthenticator.authenticate( authDataSource, httpServletRequest.getSession( true ) ); @@ -162,45 +163,43 @@ public class DefaultAuthenticationService { if ( authenticationFailureCause.getCause() == AuthenticationConstants.AUTHN_NO_SUCH_USER ) { - errorMessages.add( new ErrorMessage( "redback:incorrect.username.password" ) ); + errorMessages.add( ErrorMessage.of( ERR_AUTH_INVALID_CREDENTIALS ) ); } else { - errorMessages.add( new ErrorMessage().message( "redback:"+authenticationFailureCause.getMessage() ) ); + errorMessages.add( ErrorMessage.of( ERR_AUTH_FAIL_MSG, authenticationFailureCause.getMessage() ) ); } } response.setHeader( "WWW-Authenticate", "redback-login realm="+httpServletRequest.getRemoteHost() ); throw new RedbackServiceException( errorMessages , Response.Status.UNAUTHORIZED.getStatusCode()); } response.setHeader( "WWW-Authenticate", "redback-login realm="+httpServletRequest.getRemoteHost() ); - throw new RedbackServiceException( "redback:login-failed", Response.Status.UNAUTHORIZED.getStatusCode() ); + throw new RedbackServiceException( ErrorMessage.of( ERR_AUTH_FAIL_MSG ), Response.Status.UNAUTHORIZED.getStatusCode() ); } catch ( AuthenticationException e ) { log.debug( "Authentication error: {}", e.getMessage( ), e ); - throw new RedbackServiceException( "redback:login-failed", Response.Status.UNAUTHORIZED.getStatusCode() ); + throw new RedbackServiceException(ErrorMessage.of( ERR_AUTH_FAIL_MSG ), Response.Status.UNAUTHORIZED.getStatusCode() ); } catch ( UserNotFoundException e ) { log.debug( "User not found: {}", e.getMessage( ), e ); - throw new RedbackServiceException( "redback:login-failed", Response.Status.UNAUTHORIZED.getStatusCode() ); + throw new RedbackServiceException( ErrorMessage.of( ERR_AUTH_INVALID_CREDENTIALS ), Response.Status.UNAUTHORIZED.getStatusCode() ); } catch (AccountLockedException e) { log.info( "Account locked: {}", e.getMessage( ), e ); - throw new RedbackServiceException( "redback:account-locked", Response.Status.FORBIDDEN.getStatusCode() ); + throw new RedbackServiceException( ErrorMessage.of( ERR_AUTH_ACCOUNT_LOCKED ), Response.Status.FORBIDDEN.getStatusCode() ); } catch ( MustChangePasswordException e ) { log.debug( "Password change required: {}", e.getMessage( ), e ); - throw new RedbackServiceException( "redback:password-change-required", Response.Status.FORBIDDEN.getStatusCode( ) ); + throw new RedbackServiceException( ErrorMessage.of( ERR_AUTH_PASSWORD_CHANGE_REQUIRED ), Response.Status.FORBIDDEN.getStatusCode( ) ); } catch ( UserManagerException e ) { log.warn( "UserManagerException: {}", e.getMessage() ); - List<ErrorMessage> errorMessages = - Arrays.asList( new ErrorMessage().message( "UserManagerException: " + e.getMessage() ) ); - throw new RedbackServiceException( errorMessages ); + throw new RedbackServiceException( ErrorMessage.of( ERR_AUTH_USERMANAGER_FAIL, e.getMessage( ) ) ); } } @@ -210,7 +209,7 @@ public class DefaultAuthenticationService { if (!GrantType.REFRESH_TOKEN.equals(request.getGrantType())) { log.debug( "Bad grant type {}, expected: refresh_token", request.getGrantType( ).name( ).toLowerCase( ) ); - throw new RedbackServiceException( "redback:bad_grant", Response.Status.FORBIDDEN.getStatusCode( ) ); + throw new RedbackServiceException( ErrorMessage.of( ERR_AUTH_UNSUPPORTED_GRANT_TYPE, request.getGrantType().getLabel() ), Response.Status.FORBIDDEN.getStatusCode( ) ); } try { @@ -222,7 +221,7 @@ public class DefaultAuthenticationService } catch ( TokenAuthenticationException e ) { - throw new RedbackServiceException( e.getError( ).getError( ), Response.Status.UNAUTHORIZED.getStatusCode( ) ); + throw new RedbackServiceException( ErrorMessage.of(ERR_AUTH_INVALID_TOKEN, e.getError( ).getError( )), Response.Status.UNAUTHORIZED.getStatusCode( ) ); } } @@ -235,7 +234,7 @@ public class DefaultAuthenticationService { return buildRestUser( pri.getUser( ) ); } else { - throw new RedbackServiceException( "redback:not_authenticated", Response.Status.UNAUTHORIZED.getStatusCode( ) ); + throw new RedbackServiceException( ErrorMessage.of( ERR_AUTH_UNAUTHORIZED_REQUEST ), Response.Status.UNAUTHORIZED.getStatusCode( ) ); } } 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 ff70ea7..d5610ac 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 @@ -27,6 +27,7 @@ import org.apache.archiva.redback.common.ldap.role.LdapGroup; import org.apache.archiva.redback.common.ldap.role.LdapRoleMapper; import org.apache.archiva.redback.common.ldap.role.LdapRoleMapperConfiguration; import org.apache.archiva.redback.rest.api.model.ActionStatus; +import org.apache.archiva.redback.rest.api.model.ErrorMessage; import org.apache.archiva.redback.rest.api.model.Group; import org.apache.archiva.redback.rest.api.model.v2.GroupMapping; import org.apache.archiva.redback.rest.api.model.v2.PagedResult; @@ -51,6 +52,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import static org.apache.archiva.redback.rest.api.Constants.*; + /** * * LDAP implementation of the group service @@ -106,10 +109,13 @@ public class DefaultGroupService List<LdapGroup> groups = ldapRoleMapper.getAllGroupObjects( context ); return PagedResult.of( groups.size( ), offset, limit, groups.stream( ).skip( offset ).limit( limit ).map( DefaultGroupService::getGroupFromLdap ).collect( Collectors.toList( ) ) ); } - catch ( LdapException | MappingException e ) + catch ( LdapException e ) { - log.error( e.getMessage(), e ); - throw new RedbackServiceException( e.getMessage() ); + log.error( "LDAP Error {}", e.getMessage(), e ); + throw new RedbackServiceException( ErrorMessage.of( ERR_LDAP_GENERIC ) ); + } catch (MappingException e) { + log.error( "Mapping Error {}", e.getMessage(), e ); + throw new RedbackServiceException( ErrorMessage.of( ERR_ROLE_MAPPING, e.getMessage( ) ) ); } finally { @@ -150,7 +156,7 @@ public class DefaultGroupService catch ( LdapException e ) { log.error( "Could not create ldap connection {}", e.getMessage( ) ); - throw new RedbackServiceException( "Error while talking to group registry", 500 ); + throw new RedbackServiceException( ErrorMessage.of( ERR_LDAP_GENERIC, "Error while talking to group registry"), 500 ); } catch ( ObjectNotFoundException e ) { GroupMapping ldapGroupMapping = new GroupMapping( groupName, "", new ArrayList<>( entry.getValue( ) ) ); @@ -168,7 +174,7 @@ public class DefaultGroupService catch ( MappingException e ) { log.error( e.getMessage(), e ); - throw new RedbackServiceException( e.getMessage() ); + throw new RedbackServiceException( ErrorMessage.of( ERR_ROLE_MAPPING, e.getMessage( ) ) ); } } @@ -189,7 +195,7 @@ public class DefaultGroupService catch ( MappingException e ) { log.error( e.getMessage(), e ); - throw new RedbackServiceException( e.getMessage() ); + throw new RedbackServiceException( ErrorMessage.of( ERR_ROLE_MAPPING, e.getMessage( ) ) ); } return ActionStatus.SUCCESS; } @@ -205,7 +211,7 @@ public class DefaultGroupService catch ( MappingException e ) { log.error( e.getMessage(), e ); - throw new RedbackServiceException( e.getMessage() ); + throw new RedbackServiceException( ErrorMessage.of( ERR_ROLE_MAPPING, e.getMessage( ) ) ); } return ActionStatus.SUCCESS; } @@ -219,7 +225,7 @@ public class DefaultGroupService } catch ( MappingException e ) { - throw new RedbackServiceException( "Group mapping not found ", 404 ); + throw new RedbackServiceException( ErrorMessage.of( ERR_ROLE_MAPPING_NOT_FOUND), 404 ); } try { @@ -230,7 +236,7 @@ public class DefaultGroupService catch ( MappingException e ) { log.error( "Could not update mapping {}", e.getMessage( ) ); - throw new RedbackServiceException( e.getMessage( ) ); + throw new RedbackServiceException( ErrorMessage.of( ERR_ROLE_MAPPING, e.getMessage( ) ) ); } } diff --git a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultUserService.java b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultUserService.java index 63bc816..b69db52 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultUserService.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/v2/DefaultUserService.java @@ -45,16 +45,16 @@ import org.apache.archiva.redback.rest.api.model.ActionStatus; import org.apache.archiva.redback.rest.api.model.AvailabilityStatus; import org.apache.archiva.redback.rest.api.model.ErrorMessage; import org.apache.archiva.redback.rest.api.model.Operation; -import org.apache.archiva.redback.rest.api.model.v2.PagedResult; import org.apache.archiva.redback.rest.api.model.PasswordStatus; import org.apache.archiva.redback.rest.api.model.Permission; -import org.apache.archiva.redback.rest.api.model.v2.PingResult; import org.apache.archiva.redback.rest.api.model.RegistrationKey; import org.apache.archiva.redback.rest.api.model.ResetPasswordRequest; import org.apache.archiva.redback.rest.api.model.Resource; +import org.apache.archiva.redback.rest.api.model.VerificationStatus; +import org.apache.archiva.redback.rest.api.model.v2.PagedResult; +import org.apache.archiva.redback.rest.api.model.v2.PingResult; import org.apache.archiva.redback.rest.api.model.v2.User; import org.apache.archiva.redback.rest.api.model.v2.UserRegistrationRequest; -import org.apache.archiva.redback.rest.api.model.VerificationStatus; import org.apache.archiva.redback.rest.api.services.RedbackServiceException; import org.apache.archiva.redback.rest.api.services.v2.UserService; import org.apache.archiva.redback.rest.services.RedbackAuthenticationThreadLocal; @@ -77,8 +77,10 @@ import javax.inject.Named; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -86,6 +88,8 @@ import java.util.Collections; import java.util.List; import java.util.Set; +import static org.apache.archiva.redback.rest.api.Constants.*; + @Service( "v2.userService#rest" ) public class DefaultUserService implements UserService @@ -145,6 +149,12 @@ public class DefaultUserService @Context private HttpServletRequest httpServletRequest; + @Context + private HttpServletResponse httpServletResponse; + + @Context + private UriInfo uriInfo; + @Inject public DefaultUserService( @Named( value = "userManager#default" ) UserManager userManager, SecuritySystem securitySystem ) @@ -164,8 +174,9 @@ public class DefaultUserService org.apache.archiva.redback.users.User u = userManager.findUser( user.getUserId() ); if ( u != null ) { + httpServletResponse.setHeader( "Location", uriInfo.getAbsolutePathBuilder( ).path( u.getUsername( ) ).build( ).toString( ) ); throw new RedbackServiceException( - new ErrorMessage( "user " + user.getUserId() + " already exists" ) ); + ErrorMessage.of( ERR_USER_EXISTS, user.getUserId() ), 303 ); } } catch ( UserNotFoundException e ) @@ -175,23 +186,23 @@ public class DefaultUserService } catch ( UserManagerException e ) { - throw new RedbackServiceException( new ErrorMessage( e.getMessage() ) ); + throw new RedbackServiceException( ErrorMessage.of( ERR_UNKNOWN, e.getMessage() ) ); } // data validation if ( StringUtils.isEmpty( user.getUserId() ) ) { - throw new RedbackServiceException( new ErrorMessage( "username cannot be empty" ) ); + throw new RedbackServiceException( ErrorMessage.of( ERR_USER_ID_EMPTY ), 405 ); } if ( StringUtils.isEmpty( user.getFullName() ) ) { - throw new RedbackServiceException( new ErrorMessage( "fullName cannot be empty" ) ); + throw new RedbackServiceException( ErrorMessage.of( ERR_USER_FULL_NAME_EMPTY ), 405 ); } if ( StringUtils.isEmpty( user.getEmail() ) ) { - throw new RedbackServiceException( new ErrorMessage( "email cannot be empty" ) ); + throw new RedbackServiceException( ErrorMessage.of( ERR_USER_EMAIL_EMPTY ), 405 ); } try @@ -220,15 +231,17 @@ public class DefaultUserService } roleManager.assignRole( RedbackRoleConstants.REGISTERED_USER_ROLE_ID, u.getUsername() ); + httpServletResponse.setStatus( 201 ); + httpServletResponse.setHeader( "Location", uriInfo.getAbsolutePathBuilder().path( user.getUserId() ).build( ).toString() ); } catch ( RoleManagerException rpe ) { log.error( "RoleProfile Error: {}", rpe.getMessage(), rpe ); - throw new RedbackServiceException( new ErrorMessage( "assign.role.failure", null ) ); + throw new RedbackServiceException( ErrorMessage.of(ERR_USER_ASSIGN_ROLE ) ); } catch ( UserManagerException e ) { - throw new RedbackServiceException( new ErrorMessage( e.getMessage() ) ); + throw new RedbackServiceException( ErrorMessage.of(ERR_UNKNOWN, e.getMessage() ) ); } return ActionStatus.SUCCESS; } 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 54b84ec..da80867 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 @@ -382,6 +382,19 @@ public abstract class AbstractNativeRestServices 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(); @@ -389,6 +402,7 @@ public abstract class AbstractNativeRestServices return this.adminToken; } + protected String getAdminRefreshToken() { if (this.adminRefreshToken == null) { initAdminToken(); diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeUserServiceTest.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeUserServiceTest.java index 9fecfd9..0888c19 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeUserServiceTest.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/v2/NativeUserServiceTest.java @@ -19,22 +19,36 @@ package org.apache.archiva.redback.rest.services.v2; */ import io.restassured.response.Response; -import org.apache.archiva.redback.rest.api.model.Group; +import org.apache.archiva.redback.rest.api.model.v2.User; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +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 java.util.Arrays; +import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; +import java.util.Map; import static io.restassured.RestAssured.given; import static io.restassured.http.ContentType.JSON; import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.assertEquals; /** * @author Martin Stockhammer <[email protected]> */ +@ExtendWith( SpringExtension.class ) +@ContextConfiguration( + locations = {"classpath:/ldap-spring-test.xml"} ) +@TestInstance( TestInstance.Lifecycle.PER_CLASS ) +@Tag("rest-native") +@TestMethodOrder( MethodOrderer.Random.class ) public class NativeUserServiceTest extends AbstractNativeRestServices { @Override @@ -55,21 +69,166 @@ public class NativeUserServiceTest extends AbstractNativeRestServices super.shutdownNative(); } -// @Test -// void getGroups() { -// String token = getAdminToken( ); -// Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ).when( ) -// .get( ).then( ).statusCode( 200 ).extract( ).response( ); -// assertNotNull( response ); -// List<Group> 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 getUsers() { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ).get( ).then( ).statusCode( 200 ).extract( ).response( ); + assertNotNull( response ); + List<User> userData = response.body( ).jsonPath( ).getList( "data", User.class ); + assertNotNull( userData ); + assertEquals( 2, userData.size( ) ); + assertEquals( Integer.valueOf( 0 ), response.body( ).jsonPath( ).get( "pagination.offset" ) ); + assertEquals( Integer.valueOf( 1000 ), response.body( ).jsonPath( ).get( "pagination.limit" ) ); + assertEquals( Integer.valueOf( 2 ), response.body( ).jsonPath( ).get( "pagination.totalCount" ) ); + } + + @Test + void getUsersWithoutLogin() { + given( ).spec( getRequestSpec( ) ).contentType( JSON ) + .when( ).get( ).then( ).statusCode( 403 ); + } + + @Test + void getUser() { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ).get( "admin" ).then( ).statusCode( 200 ).extract( ).response( ); + assertNotNull( response ); + assertEquals( "jpa:admin", response.body( ).jsonPath( ).get( "id" ) ); + assertEquals( "admin", response.body( ).jsonPath( ).get( "user_id" ) ); + assertEquals( "the admin user", response.body( ).jsonPath( ).get( "fullName" ) ); + } + + @Test + void getUserWithoutLogin() { + given( ).spec( getRequestSpec( ) ).contentType( JSON ) + .when( ).get( "admin" ).then( ).statusCode( 403 ); + } + + + @Test + void createUser() { + String token = getAdminToken( ); + try + { + Map<String, Object> jsonAsMap = new HashMap<>( ); + jsonAsMap.put( "user_id", "aragorn" ); + jsonAsMap.put( "email", "[email protected]" ); + jsonAsMap.put( "fullName", "Aragorn King of Gondor" ); + jsonAsMap.put( "password", "pAssw0rD" ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .body( jsonAsMap ) + .when( ) + .post( ) + .then( ).statusCode( 201 ).extract( ).response( ); + assertTrue( response.getHeader( "Location" ).endsWith( "/aragorn" ) ); + + } finally + { + given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ).delete( "aragorn").then( ).statusCode( 200 ); + + } + } + + @Test + void createInvalidUser() { + String token = getAdminToken( ); + Map<String, Object> jsonAsMap = new HashMap<>( ); + jsonAsMap.put( "user_id", "" ); + jsonAsMap.put( "email", "[email protected]" ); + jsonAsMap.put( "fullName", "Aragorn King of Gondor" ); + jsonAsMap.put( "password", "pAssw0rD" ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .body( jsonAsMap ) + .when( ) + .post( ) + .then( ).statusCode( 405 ).extract( ).response( ); + + } + + + @Test + void createUserAndPermissionFail() { + String token = getAdminToken( ); + try + { + Map<String, Object> jsonAsMap = new HashMap<>( ); + jsonAsMap.put( "user_id", "aragorn" ); + jsonAsMap.put( "email", "[email protected]" ); + jsonAsMap.put( "fullName", "Aragorn King of Gondor" ); + jsonAsMap.put( "validated", true ); + jsonAsMap.put( "password", "pAssw0rD" ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .body( jsonAsMap ) + .when( ) + .post( ) + .then( ).statusCode( 201 ).extract( ).response( ); + assertTrue( response.getHeader( "Location" ).endsWith( "/aragorn" ) ); + + String userToken = getUserToken( "aragorn", "pAssw0rD" ); + + jsonAsMap = new HashMap<>( ); + jsonAsMap.put( "user_id", "arwen" ); + jsonAsMap.put( "email", "[email protected]" ); + jsonAsMap.put( "fullName", "Arwen Daughter of Elrond" ); + jsonAsMap.put( "password", "pAssw0rD" ); + given( ).spec( getRequestSpec( userToken ) ).contentType( JSON ) + .body( jsonAsMap ) + .when( ) + .post( ) + .then( ).statusCode( 403 ); + + + } finally + { + given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ).delete( "aragorn").then( ).statusCode( 200 ); + + } + } + + @Test + void createUserExistsAlready() { + String token = getAdminToken( ); + try + { + Map<String, Object> jsonAsMap = new HashMap<>( ); + jsonAsMap.put( "user_id", "aragorn" ); + jsonAsMap.put( "email", "[email protected]" ); + jsonAsMap.put( "fullName", "Aragorn King of Gondor" ); + jsonAsMap.put( "validated", true ); + jsonAsMap.put( "password", "pAssw0rD" ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .body( jsonAsMap ) + .when( ) + .post( ) + .then( ).statusCode( 201 ).extract( ).response( ); + assertTrue( response.getHeader( "Location" ).endsWith( "/aragorn" ) ); + + jsonAsMap = new HashMap<>( ); + jsonAsMap.put( "user_id", "aragorn" ); + jsonAsMap.put( "email", "[email protected]" ); + jsonAsMap.put( "fullName", "Aragorn King of Gondor" ); + jsonAsMap.put( "validated", true ); + jsonAsMap.put( "password", "pAssw0rD" ); + + response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .body( jsonAsMap ) + .when( ) + .redirects().follow( false ) // Rest assured default is following the 303 redirect + .post( ) + .prettyPeek() + .peek() + .then( ).statusCode( 303 ).extract().response(); + assertTrue( response.getHeader( "Location" ).endsWith( "/aragorn" ) ); + } finally + { + given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ).delete( "aragorn").then( ).statusCode( 200 ); + + } + } }
