Spring Security 如何在 Spring 云合约测试中模拟Principal?

e1xvtsh3  于 2023-01-26  发布在  Spring
关注(0)|答案(3)|浏览(149)

在REST控制器中,我有几个方法需要创建契约测试,但我不知道如何提供Principal来通过测试。
控制器中的方法之一,其参数中包含Principal:

@PreAuthorize("hasRole('USER')")
    @GetMapping("/current")
    public Details getCurrent(Principal principal) {
        return houseManager.getById(Principals.getCurrentUserId(principal));
    }

我已经为测试创建了基类:

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = {Controller.class})
@ContextConfiguration(classes = {TestConfig.class, ControllerTestConfig.class})
@ComponentScan(basePackageClasses = {Controller.class})
@AutoConfigureStubRunner
public class ControllersWithSecurityBase {
    @Autowired 
    privet Service service;
    @Autowired
    WebApplicationContext context;
    @Mock
    private Principal mockedPrincipal;

    RestAssuredMockMvc.standaloneSetup(new Controller(service));
    RequestBuilder requestBuilder = MockMvcRequestBuilders
                .get("/") 
                .with(user("user")
                        .password("password")
                        .roles("USER"))
                .principal(mockedPrincipal)
                .accept(MediaType.APPLICATION_JSON);
        MockMvc mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .defaultRequest(requestBuilder)
                .apply(springSecurity())
                .build();
        RestAssuredMockMvc.mockMvc(mockMvc);
}

合同:

Contract.make {
    name("Should find current by principal")
    request {
        method(GET)
        urlPath(".../current")
    }

    response {
        status(200)
    }
}

作为mvn干净安装的结果,我有下一个异常:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.ClassCastException: org.springframework.security.authentication.UsernamePasswordAuthenticationToken cannot be cast to java.util.Map

我需要做什么才能正确地嘲笑校长并通过考试?

ssm49v7z

ssm49v7z1#

当您设置基类并确信需要使用AuthenticationPrincipalArgumentResolver传递自定义参数解析器时

mockMvc(
                standaloneSetup( controller )
                        .setCustomArgumentResolvers( new AuthenticationPrincipalArgumentResolver() )

您还可以传入插件,该插件将在每个测试中添加WithMockUser

<build>
        <plugin>
            <groupId>com.google.code.maven-replacer-plugin</groupId>
            <artifactId>maven-replacer-plugin</artifactId>
            <version>${maven-replacer-plugin.version}</version>
            <executions>
                <execution>
                    <phase>generate-test-sources</phase>
                    <goals>
                        <goal>replace</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <includes>
                    <include>target/generated-test-sources/**/*.java</include>
                </includes>
                <regex>true</regex>
                <regexFlags>
                    <regexFlag>MULTILINE</regexFlag>
                </regexFlags>
                <replacements>
                    <replacement>
                        <token>@Test</token>
                        <value>@WithMockUser
@Test</value>
                    </replacement>
                </replacements>
            </configuration>
        </plugin>
    </plugins>
</build>

记住将WithMockUser作为完全限定名传递。

nwlls2ji

nwlls2ji2#

我的项目使用Oauth2安全性。
因此,为了在契约测试中模拟Principal对象,我创建了OAuth2AuthenticationDetails的bean(该类实现了Principal接口)。
具有Bean OAuth2AuthenticationDetails的类配置为:

package com.example.config.fakesecurityconfig;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;

import java.util.*;

@Configuration
public class OAuth2TestConfig {

    @Bean
    public OAuth2Authentication oAuth2Authentication() {
        return new OAuth2Authentication(getStoredRequest(), getUserAuthentication());
    }

    @Bean
    public OAuth2AuthenticationDetails oAuth2AuthenticationDetails() {
        MockHttpServletRequest request = new MockHttpServletRequest();
        return new OAuth2AuthenticationDetails(request);
    }

    private OAuth2Request getStoredRequest() {
        Set<String> scope = new HashSet<>();
        scope.add("read");
        scope.add("write");
        return new OAuth2Request(
                Collections.EMPTY_MAP,
                "clientId",
                getGrantedAuthorityCollection(),
                true,
                scope,
                Collections.EMPTY_SET,
                null,
                Collections.EMPTY_SET,
                Collections.EMPTY_MAP);
    }

    private Authentication getUserAuthentication() {
        String credentials = "PROTECTED";
        Authentication authentication = new TestingAuthenticationToken(getPrincipalMap(), credentials, getGrantedAuthorityAsList());
        return new OAuth2Authentication(getStoredRequest(), authentication);
    }

    private Map<String, String> getPrincipalMap() {
        Map<String, String> principalMap = new LinkedHashMap<>();
        principalMap.put("id", "5c49c98d3a0f3a23cd39a720");
        principalMap.put("username", "TestUserName");
        principalMap.put("password", "TestPassword");
        principalMap.put("createdAt", "2018-06-14 10:35:05");
        principalMap.put("userType", "USER");
        principalMap.put("authorities", getGrantedAuthorityCollectionAsMap().toString());
        principalMap.put("accountNonExpired", "true");
        principalMap.put("accountNonLocked", "true");
        principalMap.put("credentialsNonExpired", "true");
        principalMap.put("enabled", "true");
        principalMap.put("uniqueId", "null");
        principalMap.put("uniqueLink", "fc3552f4-0cdf-494d-bc46-9d1e6305400a");
        principalMap.put("uniqueLinkCreatedAt", "2019-09-06 10:44:36");
        principalMap.put("someId", "59b5a82c410df8000a83a1ff");
        principalMap.put("otherId", "59b5a82c410df8000a83a1ff");
        principalMap.put("name", "TestName");
        return principalMap;
    }

    private Collection<GrantedAuthority> getGrantedAuthorityCollection() {
        return Arrays.asList(
                new SimpleGrantedAuthority("ROLE_ADMIN"),
                new SimpleGrantedAuthority("ROLE_USER")
        );
    }

    private List<GrantedAuthority> getGrantedAuthorityAsList() {
        return new ArrayList<>(getGrantedAuthorityCollection());
    }

    private LinkedHashMap<String, GrantedAuthority> getGrantedAuthorityCollectionAsMap() {
        LinkedHashMap<String, GrantedAuthority> map = new LinkedHashMap<>();
        for (GrantedAuthority authority : getGrantedAuthorityCollection()) {
            map.put("authority", authority);
        }
        return map;
    }
}

因此,我的合同测试基类是:

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = {Controller.class})
@ContextConfiguration(classes = {TestConfig.class, OAuth2TestConfig.class})
@ComponentScan(basePackageClasses = {Controller.class})
@AutoConfigureStubRunner
@WebAppConfiguration
public abstract class HousesControllersSecuredBase {
    @Autowired
    private Service service;
    @Autowired
    private WebApplicationContext context;
    @Autowired
    private OAuth2Authentication oAuth2Authentication;
    @Autowired
    private OAuth2AuthenticationDetails oAuth2AuthenticationDetails;
    @Autowired
    private MockMvc mockMvc;

    @Before
    public void settingUpTests() {
        RestAssuredMockMvc.standaloneSetup(Controller(houseService));
        mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .build();
        RestAssuredMockMvc.mockMvc(mockMvc);
        oAuth2Authentication.setDetails(oAuth2AuthenticationDetails);
        RestAssuredMockMvc.authentication = 
            RestAssuredMockMvc.principal(oAuth2Authentication);
    }

    @After
    public void ShuttingDownTests() {
        RestAssuredMockMvc.reset();
    }
}
klsxnrf1

klsxnrf13#

在基本测试中添加@WithMockUser对我很有效。

import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.context.WebApplicationContext;

@SpringBootTest 
@WithMockUser //this will ensure a mock user will be injected to all requests
public abstract class BaseTestCloudContract {

    @Autowired
    private WebApplicationContext context;

    @BeforeEach
    public void setup() {
        RestAssuredMockMvc.webAppContextSetup(context);
    }
}

相关问题