Improving V2 REST services

This commit is contained in:
Martin Stockhammer 2020-07-26 21:10:44 +02:00
parent 8e6023173d
commit 8242f07b08
7 changed files with 277 additions and 58 deletions

View File

@ -21,7 +21,31 @@ package org.apache.archiva.redback.rest.api;
/** /**
* @author Martin Stockhammer <martin_s@apache.org> * @author Martin Stockhammer <martin_s@apache.org>
*/ */
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";
} }

View File

@ -57,6 +57,10 @@ public class ErrorMessage
this.args = args; this.args = args;
} }
public static ErrorMessage of(String errorKey, String... args) {
return new ErrorMessage( errorKey, args );
}
public String getErrorKey() public String getErrorKey()
{ {
return errorKey; return errorKey;

View File

@ -31,11 +31,11 @@ import org.apache.archiva.redback.policy.AccountLockedException;
import org.apache.archiva.redback.policy.MustChangePasswordException; import org.apache.archiva.redback.policy.MustChangePasswordException;
import org.apache.archiva.redback.rest.api.model.ErrorMessage; 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.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.TokenResponse;
import org.apache.archiva.redback.rest.api.model.User; 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.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.RedbackServiceException;
import org.apache.archiva.redback.rest.api.services.v2.AuthenticationService; import org.apache.archiva.redback.rest.api.services.v2.AuthenticationService;
import org.apache.archiva.redback.rest.services.interceptors.RedbackPrincipal; 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 javax.ws.rs.core.SecurityContext;
import java.security.Principal; import java.security.Principal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import static org.apache.archiva.redback.rest.api.Constants.*;
/** /**
* *
* Authentication service provides REST methods for authentication and verification. * Authentication service provides REST methods for authentication and verification.
@ -127,7 +128,7 @@ public class DefaultAuthenticationService
throws RedbackServiceException throws RedbackServiceException
{ {
if (!GrantType.AUTHORIZATION_CODE.equals(loginRequest.getGrantType())) { 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(); String userName = loginRequest.getUserId(), password = loginRequest.getPassword();
PasswordBasedAuthenticationDataSource authDataSource = PasswordBasedAuthenticationDataSource authDataSource =
@ -146,7 +147,7 @@ public class DefaultAuthenticationService
if ( !user.isValidated() ) if ( !user.isValidated() )
{ {
log.info( "user {} not validated", user.getUsername() ); 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 // Stateless services no session
// httpAuthenticator.authenticate( authDataSource, httpServletRequest.getSession( true ) ); // httpAuthenticator.authenticate( authDataSource, httpServletRequest.getSession( true ) );
@ -162,45 +163,43 @@ public class DefaultAuthenticationService
{ {
if ( authenticationFailureCause.getCause() == AuthenticationConstants.AUTHN_NO_SUCH_USER ) 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 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() ); response.setHeader( "WWW-Authenticate", "redback-login realm="+httpServletRequest.getRemoteHost() );
throw new RedbackServiceException( errorMessages , Response.Status.UNAUTHORIZED.getStatusCode()); throw new RedbackServiceException( errorMessages , Response.Status.UNAUTHORIZED.getStatusCode());
} }
response.setHeader( "WWW-Authenticate", "redback-login realm="+httpServletRequest.getRemoteHost() ); 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 ) catch ( AuthenticationException e )
{ {
log.debug( "Authentication error: {}", e.getMessage( ), 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 ) catch ( UserNotFoundException e )
{ {
log.debug( "User not found: {}", e.getMessage( ), 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) { catch (AccountLockedException e) {
log.info( "Account locked: {}", e.getMessage( ), 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 ) catch ( MustChangePasswordException e )
{ {
log.debug( "Password change required: {}", e.getMessage( ), 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 ) catch ( UserManagerException e )
{ {
log.warn( "UserManagerException: {}", e.getMessage() ); log.warn( "UserManagerException: {}", e.getMessage() );
List<ErrorMessage> errorMessages = throw new RedbackServiceException( ErrorMessage.of( ERR_AUTH_USERMANAGER_FAIL, e.getMessage( ) ) );
Arrays.asList( new ErrorMessage().message( "UserManagerException: " + e.getMessage() ) );
throw new RedbackServiceException( errorMessages );
} }
} }
@ -210,7 +209,7 @@ public class DefaultAuthenticationService
{ {
if (!GrantType.REFRESH_TOKEN.equals(request.getGrantType())) { if (!GrantType.REFRESH_TOKEN.equals(request.getGrantType())) {
log.debug( "Bad grant type {}, expected: refresh_token", request.getGrantType( ).name( ).toLowerCase( ) ); 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 try
{ {
@ -222,7 +221,7 @@ public class DefaultAuthenticationService
} }
catch ( TokenAuthenticationException e ) 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( ) ); return buildRestUser( pri.getUser( ) );
} else { } else {
throw new RedbackServiceException( "redback:not_authenticated", Response.Status.UNAUTHORIZED.getStatusCode( ) ); throw new RedbackServiceException( ErrorMessage.of( ERR_AUTH_UNAUTHORIZED_REQUEST ), Response.Status.UNAUTHORIZED.getStatusCode( ) );
} }
} }

View File

@ -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.LdapRoleMapper;
import org.apache.archiva.redback.common.ldap.role.LdapRoleMapperConfiguration; 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.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.Group;
import org.apache.archiva.redback.rest.api.model.v2.GroupMapping; import org.apache.archiva.redback.rest.api.model.v2.GroupMapping;
import org.apache.archiva.redback.rest.api.model.v2.PagedResult; 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.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.archiva.redback.rest.api.Constants.*;
/** /**
* *
* LDAP implementation of the group service * LDAP implementation of the group service
@ -106,10 +109,13 @@ public class DefaultGroupService
List<LdapGroup> groups = ldapRoleMapper.getAllGroupObjects( context ); 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( ) ) ); 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 ); log.error( "LDAP Error {}", e.getMessage(), e );
throw new RedbackServiceException( e.getMessage() ); 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 finally
{ {
@ -150,7 +156,7 @@ public class DefaultGroupService
catch ( LdapException e ) catch ( LdapException e )
{ {
log.error( "Could not create ldap connection {}", e.getMessage( ) ); 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 ) { catch ( ObjectNotFoundException e ) {
GroupMapping ldapGroupMapping = new GroupMapping( groupName, "", new ArrayList<>( entry.getValue( ) ) ); GroupMapping ldapGroupMapping = new GroupMapping( groupName, "", new ArrayList<>( entry.getValue( ) ) );
@ -168,7 +174,7 @@ public class DefaultGroupService
catch ( MappingException e ) catch ( MappingException e )
{ {
log.error( e.getMessage(), 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 ) catch ( MappingException e )
{ {
log.error( e.getMessage(), e ); log.error( e.getMessage(), e );
throw new RedbackServiceException( e.getMessage() ); throw new RedbackServiceException( ErrorMessage.of( ERR_ROLE_MAPPING, e.getMessage( ) ) );
} }
return ActionStatus.SUCCESS; return ActionStatus.SUCCESS;
} }
@ -205,7 +211,7 @@ public class DefaultGroupService
catch ( MappingException e ) catch ( MappingException e )
{ {
log.error( e.getMessage(), e ); log.error( e.getMessage(), e );
throw new RedbackServiceException( e.getMessage() ); throw new RedbackServiceException( ErrorMessage.of( ERR_ROLE_MAPPING, e.getMessage( ) ) );
} }
return ActionStatus.SUCCESS; return ActionStatus.SUCCESS;
} }
@ -219,7 +225,7 @@ public class DefaultGroupService
} }
catch ( MappingException e ) catch ( MappingException e )
{ {
throw new RedbackServiceException( "Group mapping not found ", 404 ); throw new RedbackServiceException( ErrorMessage.of( ERR_ROLE_MAPPING_NOT_FOUND), 404 );
} }
try try
{ {
@ -230,7 +236,7 @@ public class DefaultGroupService
catch ( MappingException e ) catch ( MappingException e )
{ {
log.error( "Could not update mapping {}", e.getMessage( ) ); log.error( "Could not update mapping {}", e.getMessage( ) );
throw new RedbackServiceException( e.getMessage( ) ); throw new RedbackServiceException( ErrorMessage.of( ERR_ROLE_MAPPING, e.getMessage( ) ) );
} }
} }

View File

@ -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.AvailabilityStatus;
import org.apache.archiva.redback.rest.api.model.ErrorMessage; 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.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.PasswordStatus;
import org.apache.archiva.redback.rest.api.model.Permission; 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.RegistrationKey;
import org.apache.archiva.redback.rest.api.model.ResetPasswordRequest; 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.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.User;
import org.apache.archiva.redback.rest.api.model.v2.UserRegistrationRequest; 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.RedbackServiceException;
import org.apache.archiva.redback.rest.api.services.v2.UserService; import org.apache.archiva.redback.rest.api.services.v2.UserService;
import org.apache.archiva.redback.rest.services.RedbackAuthenticationThreadLocal; 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.AddressException;
import javax.mail.internet.InternetAddress; import javax.mail.internet.InternetAddress;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -86,6 +88,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.apache.archiva.redback.rest.api.Constants.*;
@Service( "v2.userService#rest" ) @Service( "v2.userService#rest" )
public class DefaultUserService public class DefaultUserService
implements UserService implements UserService
@ -145,6 +149,12 @@ public class DefaultUserService
@Context @Context
private HttpServletRequest httpServletRequest; private HttpServletRequest httpServletRequest;
@Context
private HttpServletResponse httpServletResponse;
@Context
private UriInfo uriInfo;
@Inject @Inject
public DefaultUserService( @Named( value = "userManager#default" ) UserManager userManager, public DefaultUserService( @Named( value = "userManager#default" ) UserManager userManager,
SecuritySystem securitySystem ) SecuritySystem securitySystem )
@ -164,8 +174,9 @@ public class DefaultUserService
org.apache.archiva.redback.users.User u = userManager.findUser( user.getUserId() ); org.apache.archiva.redback.users.User u = userManager.findUser( user.getUserId() );
if ( u != null ) if ( u != null )
{ {
httpServletResponse.setHeader( "Location", uriInfo.getAbsolutePathBuilder( ).path( u.getUsername( ) ).build( ).toString( ) );
throw new RedbackServiceException( throw new RedbackServiceException(
new ErrorMessage( "user " + user.getUserId() + " already exists" ) ); ErrorMessage.of( ERR_USER_EXISTS, user.getUserId() ), 303 );
} }
} }
catch ( UserNotFoundException e ) catch ( UserNotFoundException e )
@ -175,23 +186,23 @@ public class DefaultUserService
} }
catch ( UserManagerException e ) catch ( UserManagerException e )
{ {
throw new RedbackServiceException( new ErrorMessage( e.getMessage() ) ); throw new RedbackServiceException( ErrorMessage.of( ERR_UNKNOWN, e.getMessage() ) );
} }
// data validation // data validation
if ( StringUtils.isEmpty( user.getUserId() ) ) 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() ) ) 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() ) ) 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 try
@ -220,15 +231,17 @@ public class DefaultUserService
} }
roleManager.assignRole( RedbackRoleConstants.REGISTERED_USER_ROLE_ID, u.getUsername() ); 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 ) catch ( RoleManagerException rpe )
{ {
log.error( "RoleProfile Error: {}", rpe.getMessage(), 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 ) catch ( UserManagerException e )
{ {
throw new RedbackServiceException( new ErrorMessage( e.getMessage() ) ); throw new RedbackServiceException( ErrorMessage.of(ERR_UNKNOWN, e.getMessage() ) );
} }
return ActionStatus.SUCCESS; return ActionStatus.SUCCESS;
} }

View File

@ -382,6 +382,19 @@ public abstract class AbstractNativeRestServices
this.adminRefreshToken = result.body( ).jsonPath( ).getString( "refresh_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() { protected String getAdminToken() {
if (this.adminToken == null) { if (this.adminToken == null) {
initAdminToken(); initAdminToken();
@ -389,6 +402,7 @@ public abstract class AbstractNativeRestServices
return this.adminToken; return this.adminToken;
} }
protected String getAdminRefreshToken() { protected String getAdminRefreshToken() {
if (this.adminRefreshToken == null) { if (this.adminRefreshToken == null) {
initAdminToken(); initAdminToken();

View File

@ -19,22 +19,36 @@ package org.apache.archiva.redback.rest.services.v2;
*/ */
import io.restassured.response.Response; 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.AfterAll;
import org.junit.jupiter.api.BeforeAll; 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.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.List;
import java.util.stream.Collectors; import java.util.Map;
import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.given;
import static io.restassured.http.ContentType.JSON; import static io.restassured.http.ContentType.JSON;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* @author Martin Stockhammer <martin_s@apache.org> * @author Martin Stockhammer <martin_s@apache.org>
*/ */
@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 public class NativeUserServiceTest extends AbstractNativeRestServices
{ {
@Override @Override
@ -55,21 +69,166 @@ public class NativeUserServiceTest extends AbstractNativeRestServices
super.shutdownNative(); super.shutdownNative();
} }
// @Test @Test
// void getGroups() { void getUsers() {
// String token = getAdminToken( ); String token = getAdminToken( );
// Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ).when( ) Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
// .get( ).then( ).statusCode( 200 ).extract( ).response( ); .when( ).get( ).then( ).statusCode( 200 ).extract( ).response( );
// assertNotNull( response ); assertNotNull( response );
// List<Group> data = response.body( ).jsonPath( ).getList( "data", Group.class ); List<User> userData = response.body( ).jsonPath( ).getList( "data", User.class );
// assertNotNull( data ); assertNotNull( userData );
// assertEquals( Integer.valueOf( 0 ), response.body( ).jsonPath( ).get( "pagination.offset" ) ); assertEquals( 2, userData.size( ) );
// assertEquals( Integer.valueOf( 1000 ), response.body( ).jsonPath( ).get( "pagination.limit" ) ); assertEquals( Integer.valueOf( 0 ), response.body( ).jsonPath( ).get( "pagination.offset" ) );
// assertEquals( Integer.valueOf( 6 ), response.body( ).jsonPath( ).get( "pagination.totalCount" ) ); assertEquals( Integer.valueOf( 1000 ), response.body( ).jsonPath( ).get( "pagination.limit" ) );
// assertEquals( 6, data.size( ) ); assertEquals( Integer.valueOf( 2 ), response.body( ).jsonPath( ).get( "pagination.totalCount" ) );
// 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 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", "aragorn@lordoftherings.org" );
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", "aragorn@lordoftherings.org" );
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", "aragorn@lordoftherings.org" );
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", "arwen@lordoftherings.org" );
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", "aragorn@lordoftherings.org" );
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", "aragorn@lordoftherings.org" );
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 );
}
}
} }