Dans Spring Boot 1.4.1, je veux faire des tests unitaires (pas des tests d'intégration) sur une méthode de service qui a un accès restreint avec @PreAuthorize.
Le problème est que @PreAuthorize ne semble pas être vérifié lorsque lancer le test en solo depuis Eclipse (je n'ai pas encore essayé avec mvn test).
Ensuite, si j'arrive miraculeusement à exécuter le test correctement, j'essaierai de travailler avec l'interface StudyService, pas l'impl.
Voici ma classe de test:
@Service public class StudyServiceImpl implements StudyService { @Autowired private StudyRepository studyRepository; @Override @PreAuthorize("hasAnyRole('DOES NOT EVENT CHECK SYNTAX") public Study findById(final Long id) { return studyRepository.findOne(id); } }
Voici le service:
@RunWith(MockitoJUnitRunner.class) public class TestMethodSecurity { private static final Long STUDY_ID = 1L; @Mock private StudyRepository studyRepository; @InjectMocks private StudyServiceImpl studyService; @Before public void setup() { given(studyRepository.findOne(STUDY_ID)).willReturn(ModelsUtil.createStudy()); } @Test public void findByIdWithoutAccessRightTest() { Study study = studyService.findById(STUDY_ID); } }
Le test réussir, ce qui est un échec.
3 Réponses :
Si vous souhaitez tester les annotations Spring Security, vous devez utiliser SpringRunner
qui créera Spring Context et injectera le code Spring Security dans la classe proxy.
Comment tester Spring Security, vous pouvez trouver ici .
Je vous remercie. J'ai donc ajouté @RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration mais cela ne change pas le résultat (test réussi)
Annotez votre classe de test avec
public ApplicationUser getApplicationUser() { ApplicationUser applicationUser = (ApplicationUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); return applicationUser; } import org.junit.Before; import org.junit.Rule; import org.junit.Test; import static org.mockito.Mockito.when; import static org.mockito.Mockito.mock; import org.mockito.MockitoAnnotations; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import com.arpit.security.user.ApplicationUser; public class BaseTest { @Before public void setupMock() { MockitoAnnotations.initMocks(this); } @Test public void mockApplicationUser() { ApplicationUser applicationUser = mock(ApplicationUser.class); Authentication authentication = mock(Authentication.class); SecurityContext securityContext = mock(SecurityContext.class); when(securityContext.getAuthentication()).thenReturn(authentication); SecurityContextHolder.setContext(securityContext); when(SecurityContextHolder.getContext().getAuthentication().getPrincipal()).thenReturn(applicationUser); } }
Votre méthode devrait ressembler à ceci
@Test(expected = AccessDeniedException.class) @WithAnonymousUser @Test public void findByIdWithoutAccessRightTest() { Study study = studyService.findById(STUDY_ID); }
Vous ne pouvez pas tester la sécurité sans charger au moins la sécurité le contexte.
Vous pouvez consulter cet exemple:
@RunWith(SpringRunner.class) @ContextConfiguration
Extrait de: https://www.javacodegeeks.com/2017/05/mocking-spring-security-context-unit-testing. html
Et je suppose que votre méthode de service a volontairement des erreurs de syntaxe? (parenthèses manquantes et guillemets erronés?)
Sur @PreAuthorize, oui. Merci, je vais vérifier cela dès que possible.
Voilà comment je le fais fonctionner:
@RunWith(SpringRunner.class) @SpringBootTest @EnableGlobalMethodSecurity(prePostEnabled = true) @ActiveProfiles("test") public class StudySecurityTest { @Autowired private StudyService service; @MockBean private StudyRepository repository; @Test @WithAnonymousUser public void testAsAnonymous() { ... } @Test @WithMockKeycloakUser(id = LOGGED_USER_ID, username = LOGGED_USER_USERNAME, authorities = { "ROLE_USER" }) public void testAsUser() { ... } }
Si vous êtes intéressé par @WithMockKeycloakUser
, demandez-moi.
Vous voudrez peut-être examiner
@WithUserDetails
.Avez-vous trouvé une solution pour cela? J'ai le même problème - @PreAuthorize n'est pas vérifié dans les tests et les points finaux renvoient toujours http 200, alors qu'ils devraient renvoyer http 403.
@ user2551317 Oui, c'est avec @EnableGlobalMethodSecurity (prePostEnabled = true), j'écrirai une solution complète lundi si je m'en souviens.
@Julien Je vous serais très reconnaissant si vous pouviez écrire une solution complète à ce problème, j'obtiens BeanDefinitionOverrideException: Définition de bean invalide avec le nom 'metaDataSourceAdvisor' lorsque j'ajoute cette annotation. Peut-être que cela se mélange avec d'autres annotations.
@ user2551317 J'ai écrit ma solution ci-dessous. À propos de votre bug, je ne me souviens pas d'avoir celui-là, vérifiez-moi stackoverflow.com/questions/53834643/...