Skip to content

Commit

Permalink
Fix #965: Reflect changes in filtering operations on PowerAuth Server (
Browse files Browse the repository at this point in the history
…#967)

* Fix #965: Reflect changes in filtering operations on PowerAuth Server
- Change activationFlags to activationId for filtering of requested operations
- Add test for MobileTokenService
  • Loading branch information
jandusil authored Dec 21, 2023
1 parent da17b54 commit ed83f97
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ public ObjectResponse<OperationListResponse> operationList(@Parameter(hidden = t
if (auth != null) {
final String userId = auth.getUserId();
final String applicationId = auth.getApplicationId();
final List<String> activationFlags = auth.getActivationContext().getActivationFlags();
final String activationId = auth.getActivationContext().getActivationId();
final String language = locale.getLanguage();
final OperationListResponse listResponse = mobileTokenService.operationListForUser(userId, applicationId, language, activationFlags, true);
final OperationListResponse listResponse = mobileTokenService.operationListForUser(userId, applicationId, language, activationId, true);
final Date currentTimestamp = new Date();
return new MobileTokenResponse<>(listResponse, currentTimestamp);
} else {
Expand Down Expand Up @@ -211,9 +211,9 @@ public ObjectResponse<OperationListResponse> operationListAll(@Parameter(hidden
if (auth != null) {
final String userId = auth.getUserId();
final String applicationId = auth.getApplicationId();
final List<String> activationFlags = auth.getActivationContext().getActivationFlags();
final String activationId = auth.getActivationContext().getActivationId();
final String language = locale.getLanguage();
final OperationListResponse listResponse = mobileTokenService.operationListForUser(userId, applicationId, language, activationFlags, false);
final OperationListResponse listResponse = mobileTokenService.operationListForUser(userId, applicationId, language, activationId, false);
return new ObjectResponse<>(listResponse);
} else {
throw new MobileTokenAuthException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,30 +87,33 @@ public MobileTokenService(PowerAuthClient powerAuthClient, MobileTokenConverter
}

/**
* Get the operation list with operations of a given users. The service either returns only pending
* operations or all operations, depending on the provided flag.
* Retrieves a list of operations for a specified user. This method can return
* either all operations or only those that are pending, based on the 'pendingOnly' flag.
* It processes each operation detail, converts them into a consistent format, and
* filters out operations without a corresponding template.
*
* @param userId User ID.
* @param applicationId Application ID.
* @param language Language.
* @param activationFlags Activation flags to condition the operation against.
* @param pendingOnly Flag indicating if only pending or all operation should be returned.
* @return Response with pending or all operations, depending on the "pendingOnly" flag.
* @throws PowerAuthClientException In the case that PowerAuth service call fails.
* @throws MobileTokenConfigurationException In the case of system misconfiguration.
* @param userId User ID for which the operation list is requested.
* @param applicationId Application ID associated with the operations.
* @param language Language for operation template localization.
* @param activationId Optional activation ID to filter operations.
* @param pendingOnly Flag indicating whether to fetch only pending operations or all.
* @return A consolidated list of operations formatted as 'OperationListResponse'.
* @throws PowerAuthClientException If there's an issue with the PowerAuth service call.
* @throws MobileTokenConfigurationException For any system configuration issues.
*/
public OperationListResponse operationListForUser(
@NotNull String userId,
@NotNull String applicationId,
@NotNull String language,
List<String> activationFlags,
String activationId,
boolean pendingOnly) throws PowerAuthClientException, MobileTokenConfigurationException {

final OperationListForUserRequest request = new OperationListForUserRequest();
request.setUserId(userId);
request.setApplications(List.of(applicationId));
request.setPageNumber(0);
request.setPageSize(OPERATION_LIST_LIMIT);
request.setActivationId(activationId);
final MultiValueMap<String, String> queryParams = httpCustomizationService.getQueryParams();
final MultiValueMap<String, String> httpHeaders = httpCustomizationService.getHttpHeaders();
final com.wultra.security.powerauth.client.model.response.OperationListResponse operations =
Expand All @@ -120,16 +123,13 @@ public OperationListResponse operationListForUser(

final OperationListResponse responseObject = new OperationListResponse();
for (OperationDetailResponse operationDetail: operations) {
final String activationFlag = operationDetail.getActivationFlag();
if (activationFlag == null || activationFlags.contains(activationFlag)) { // only return data if there is no flag, or if flag matches flags of activation
final Optional<OperationTemplateEntity> operationTemplate = operationTemplateService.findTemplate(operationDetail.getOperationType(), language);
if (operationTemplate.isEmpty()) {
logger.warn("No template found for operationType={}, skipping the entry.", operationDetail.getOperationType());
continue;
}
final Operation operation = mobileTokenConverter.convert(operationDetail, operationTemplate.get());
responseObject.add(operation);
final Optional<OperationTemplateEntity> operationTemplate = operationTemplateService.findTemplate(operationDetail.getOperationType(), language);
if (operationTemplate.isEmpty()) {
logger.warn("No template found for operationType={}, skipping the entry.", operationDetail.getOperationType());
continue;
}
final Operation operation = mobileTokenConverter.convert(operationDetail, operationTemplate.get());
responseObject.add(operation);
}
return responseObject;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/*
* PowerAuth Enrollment Server
* Copyright (C) 2023 Wultra s.r.o.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.wultra.app.enrollmentserver.impl.service;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import com.wultra.app.enrollmentserver.database.OperationTemplateRepository;
import com.wultra.app.enrollmentserver.database.entity.OperationTemplateEntity;
import com.wultra.app.enrollmentserver.impl.service.converter.MobileTokenConverter;
import com.wultra.security.powerauth.client.PowerAuthClient;
import com.wultra.security.powerauth.client.model.request.OperationListForUserRequest;
import com.wultra.security.powerauth.client.model.response.OperationDetailResponse;
import com.wultra.security.powerauth.lib.mtoken.model.entity.Operation;
import com.wultra.security.powerauth.lib.mtoken.model.response.OperationListResponse;
import io.getlime.security.powerauth.rest.api.spring.service.HttpCustomizationService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.context.ActiveProfiles;

import java.util.HashMap;
import java.util.List;
import java.util.Optional;

/**
* Test for {@link MobileTokenService}.
*
* @author Jan Dusil, [email protected]
*/
@ExtendWith(MockitoExtension.class)
@ActiveProfiles("test")
class MobileTokenServiceTest {

@Mock
private PowerAuthClient powerAuthClient;

@Mock
private MobileTokenConverter mobileTokenConverter;

@Mock
private OperationTemplateService operationTemplateService;

@Mock
private HttpCustomizationService httpCustomizationService;

@InjectMocks
private MobileTokenService tested;

@Mock
private OperationTemplateRepository templateRepository;

private static final int OPERATION_LIST_LIMIT = 100;

@Test
void testOperationListForUser() throws Exception {
final String userId = "test-user";
final String applicationId = "21";
final String language = "CZ";
final String activationId = "test-activation";
final String operationType = "login";

final OperationListForUserRequest request = new OperationListForUserRequest();
request.setUserId(userId);
request.setApplications(List.of(applicationId));
request.setPageNumber(0);
request.setPageSize(OPERATION_LIST_LIMIT);
request.setActivationId(activationId);

final OperationDetailResponse operationDetailResponse = new OperationDetailResponse();
operationDetailResponse.setUserId(userId);
operationDetailResponse.setApplications(List.of(applicationId));
operationDetailResponse.setOperationType(operationType);
operationDetailResponse.setParameters(new HashMap<>());

final com.wultra.security.powerauth.client.model.response.OperationListResponse response
= new com.wultra.security.powerauth.client.model.response.OperationListResponse();
response.add(operationDetailResponse);

when(powerAuthClient.operationList(request, null, null)).thenReturn(response);

final OperationTemplateEntity operationTemplate = new OperationTemplateEntity();
operationTemplate.setLanguage(language);
operationTemplate.setPlaceholder(operationType);
operationTemplate.setId(1L);
when(operationTemplateService.findTemplate(operationType, language)).thenReturn(Optional.of(operationTemplate));

final Operation operation = new Operation();
operation.setName(operationType);
when(mobileTokenConverter.convert(operationDetailResponse, operationTemplate)).thenReturn(operation);

final OperationListResponse operationListResponse = tested.operationListForUser(userId, applicationId, language, activationId, false);

assertNotNull(operationListResponse);
assertEquals(1, operationListResponse.size());
assertNotNull(operationListResponse.get(0));
assertEquals(operationType, operationListResponse.get(0).getName());
}

@Test
void testPendingOperationListForUser() throws Exception {
final String userId = "test-user";
final String applicationId = "21";
final String language = "CZ";
final String activationId = "test-activation";
final String operationType = "login";

final OperationListForUserRequest request = new OperationListForUserRequest();
request.setUserId(userId);
request.setApplications(List.of(applicationId));
request.setPageNumber(0);
request.setPageSize(OPERATION_LIST_LIMIT);
request.setActivationId(activationId);

final OperationDetailResponse operationDetailResponse = new OperationDetailResponse();
operationDetailResponse.setUserId(userId);
operationDetailResponse.setApplications(List.of(applicationId));
operationDetailResponse.setOperationType(operationType);
operationDetailResponse.setParameters(new HashMap<>());

final com.wultra.security.powerauth.client.model.response.OperationListResponse response
= new com.wultra.security.powerauth.client.model.response.OperationListResponse();
response.add(operationDetailResponse);

when(powerAuthClient.operationPendingList(request, null, null)).thenReturn(response);

final OperationTemplateEntity operationTemplate = new OperationTemplateEntity();
operationTemplate.setLanguage(language);
operationTemplate.setPlaceholder(operationType);
operationTemplate.setId(1L);
when(operationTemplateService.findTemplate(operationType, language)).thenReturn(Optional.of(operationTemplate));

final Operation operation = new Operation();
operation.setName(operationType);
when(mobileTokenConverter.convert(operationDetailResponse, operationTemplate)).thenReturn(operation);

final OperationListResponse operationListResponse = tested.operationListForUser(userId, applicationId, language, activationId, true);

assertNotNull(operationListResponse);
assertEquals(1, operationListResponse.size());
assertNotNull(operationListResponse.get(0));
assertEquals(operationType, operationListResponse.get(0).getName());
}

@Test
void testOperationListForUserEmptyOperationTemplate() throws Exception {
final String userId = "test-user";
final String applicationId = "21";
final String language = "CZ";
final String activationId = "test-activation";
final String operationType = "login";

final OperationListForUserRequest request = new OperationListForUserRequest();
request.setUserId(userId);
request.setApplications(List.of(applicationId));
request.setPageNumber(0);
request.setPageSize(OPERATION_LIST_LIMIT);
request.setActivationId(activationId);

final OperationDetailResponse operationDetailResponse = new OperationDetailResponse();
operationDetailResponse.setUserId(userId);
operationDetailResponse.setApplications(List.of(applicationId));
operationDetailResponse.setOperationType(operationType);
operationDetailResponse.setParameters(new HashMap<>());

final com.wultra.security.powerauth.client.model.response.OperationListResponse response
= new com.wultra.security.powerauth.client.model.response.OperationListResponse();
response.add(operationDetailResponse);

when(powerAuthClient.operationList(request, null, null)).thenReturn(response);

final OperationTemplateEntity operationTemplate = new OperationTemplateEntity();
operationTemplate.setLanguage(language);
operationTemplate.setPlaceholder(operationType);
operationTemplate.setId(1L);

when(operationTemplateService.findTemplate(operationType, language)).thenReturn(Optional.empty());


final OperationListResponse operationListResponse = tested.operationListForUser(userId, applicationId, language, activationId, false);

assertNotNull(operationListResponse);
assertEquals(0, operationListResponse.size());
}

}

0 comments on commit ed83f97

Please sign in to comment.