2
votes

Méthode de service de test qui a @PreAuthorize avec JUnit

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.


5 commentaires

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/...


3 Réponses :


0
votes

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 .


1 commentaires

Je vous remercie. J'ai donc ajouté @RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration mais cela ne change pas le résultat (test réussi)



0
votes

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?)


1 commentaires

Sur @PreAuthorize, oui. Merci, je vais vérifier cela dès que possible.



-1
votes

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.


0 commentaires