स्प्रिंग टेस्ट और सुरक्षा: प्रमाणीकरण का मजाक कैसे उड़ाएं?


124

मैं यह पता लगाने की कोशिश कर रहा था कि अगर मेरे नियंत्रकों के URL ठीक से सुरक्षित हैं तो मैं यूनिट परीक्षण कैसे कर सकता हूं। बस किसी के आसपास चीजों को बदलने और गलती से सुरक्षा सेटिंग्स को हटा देता है।

मेरी नियंत्रक विधि इस प्रकार है:

@RequestMapping("/api/v1/resource/test") 
@Secured("ROLE_USER")
public @ResonseBody String test() {
    return "test";
}

मैं एक WebTestEnvironment की तरह सेट अप:

import javax.annotation.Resource;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.junit.Before;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration({ 
        "file:src/main/webapp/WEB-INF/spring/security.xml",
        "file:src/main/webapp/WEB-INF/spring/applicationContext.xml",
        "file:src/main/webapp/WEB-INF/spring/servlet-context.xml" })
public class WebappTestEnvironment2 {

    @Resource
    private FilterChainProxy springSecurityFilterChain;

    @Autowired
    @Qualifier("databaseUserService")
    protected UserDetailsService userDetailsService;

    @Autowired
    private WebApplicationContext wac;

    @Autowired
    protected DataSource dataSource;

    protected MockMvc mockMvc;

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    protected UsernamePasswordAuthenticationToken getPrincipal(String username) {

        UserDetails user = this.userDetailsService.loadUserByUsername(username);

        UsernamePasswordAuthenticationToken authentication = 
                new UsernamePasswordAuthenticationToken(
                        user, 
                        user.getPassword(), 
                        user.getAuthorities());

        return authentication;
    }

    @Before
    public void setupMockMvc() throws NamingException {

        // setup mock MVC
        this.mockMvc = MockMvcBuilders
                .webAppContextSetup(this.wac)
                .addFilters(this.springSecurityFilterChain)
                .build();
    }
}

अपने वास्तविक परीक्षण में मैंने ऐसा कुछ करने की कोशिश की:

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Test;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;

import eu.ubicon.webapp.test.WebappTestEnvironment;

public class CopyOfClaimTest extends WebappTestEnvironment {

    @Test
    public void signedIn() throws Exception {

        UsernamePasswordAuthenticationToken principal = 
                this.getPrincipal("test1");

        SecurityContextHolder.getContext().setAuthentication(principal);        

        super.mockMvc
            .perform(
                    get("/api/v1/resource/test")
//                    .principal(principal)
                    .session(session))
            .andExpect(status().isOk());
    }

}

मैंने इसे यहाँ उठाया:

फिर भी अगर कोई इसे बारीकी से देखता है तो केवल URL में वास्तविक अनुरोध नहीं भेजने में मदद करता है, लेकिन केवल जब फ़ंक्शन स्तर पर सेवाओं का परीक्षण करता है। मेरे मामले में एक "प्रवेश निषेध" अपवाद फेंक दिया गया था:

org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) ~[spring-security-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206) ~[spring-security-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:60) ~[spring-security-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.1.RELEASE.jar:3.2.1.RELEASE]
        ...

निम्नलिखित दो लॉग संदेश उल्लेखनीय रूप से कह रहे हैं कि किसी भी उपयोगकर्ता को यह प्रमाणित करने के लिए प्रमाणित Principalनहीं किया गया था कि काम नहीं किया गया था, या यह ओवरराइट किया गया था।

14:20:34.454 [main] DEBUG o.s.s.a.i.a.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public java.util.List test.TestController.test(); target is of class [test.TestController]; Attributes: [ROLE_USER]
14:20:34.454 [main] DEBUG o.s.s.a.i.a.MethodSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS

आपकी आयात में आपकी कंपनी का नाम, eu.ubicon प्रदर्शित है। क्या यह सुरक्षा जोखिम नहीं है?
काइल ब्रिडेनस्टाइन

2
हाय, टिप्पणी के लिए धन्यवाद! मैं देख नहीं सकता कि क्यों। यह वैसे भी ओपन सोर्स सॉफ्टवेयर है। यदि आप रुचि रखते हैं, तो नवीनतम कांटे के लिए bitbucket.org/ubicon/ubicon (या bitbucket.org/dmir_wue/everyaware ) देखें। अगर मुझे कुछ याद है तो मुझे बताएं।
मार्टिन बेकर

इस समाधान की जाँच करें (उत्तर वसंत 4 के लिए है): stackoverflow.com/questions/14308341/…
नागी अत्तिला

जवाबों:


101

जवाब के लिए पहुंचने पर मुझे एक ही समय में कोई भी आसान और लचीला नहीं मिल सकता था, फिर मुझे स्प्रिंग सुरक्षा संदर्भ मिला और मुझे एहसास हुआ कि सही समाधान के पास हैं। AOP समाधान अक्सर परीक्षण के लिए सबसे बड़ी हैं, और वसंत के साथ प्रदान करता @WithMockUser, @WithUserDetailsऔर @WithSecurityContextइस विरूपण साक्ष्य में,:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <version>4.2.2.RELEASE</version>
    <scope>test</scope>
</dependency>

ज्यादातर मामलों में, @WithUserDetailsलचीलेपन और मेरी ज़रूरत की शक्ति को इकट्ठा करता है।

@WithUserDetails कैसे काम करता है?

मूल रूप से आपको बस UserDetailsServiceउन सभी संभावित उपयोगकर्ताओं के साथ एक कस्टम बनाने की ज़रूरत है, जिन्हें आप परीक्षण करना चाहते हैं। उदाहरण के लिए

@TestConfiguration
public class SpringSecurityWebAuxTestConfig {

    @Bean
    @Primary
    public UserDetailsService userDetailsService() {
        User basicUser = new UserImpl("Basic User", "user@company.com", "password");
        UserActive basicActiveUser = new UserActive(basicUser, Arrays.asList(
                new SimpleGrantedAuthority("ROLE_USER"),
                new SimpleGrantedAuthority("PERM_FOO_READ")
        ));

        User managerUser = new UserImpl("Manager User", "manager@company.com", "password");
        UserActive managerActiveUser = new UserActive(managerUser, Arrays.asList(
                new SimpleGrantedAuthority("ROLE_MANAGER"),
                new SimpleGrantedAuthority("PERM_FOO_READ"),
                new SimpleGrantedAuthority("PERM_FOO_WRITE"),
                new SimpleGrantedAuthority("PERM_FOO_MANAGE")
        ));

        return new InMemoryUserDetailsManager(Arrays.asList(
                basicActiveUser, managerActiveUser
        ));
    }
}

अब हमारे पास हमारे उपयोगकर्ता तैयार हैं, इसलिए कल्पना करें कि हम इस नियंत्रक फ़ंक्शन तक पहुंच नियंत्रण का परीक्षण करना चाहते हैं:

@RestController
@RequestMapping("/foo")
public class FooController {

    @Secured("ROLE_MANAGER")
    @GetMapping("/salute")
    public String saluteYourManager(@AuthenticationPrincipal User activeUser)
    {
        return String.format("Hi %s. Foo salutes you!", activeUser.getUsername());
    }
}

यहां हमारे पास रूट / फू / सैल्यूट के लिए एक मैप मैप्ड फंक्शन है और हम एनोटेशन के साथ एक भूमिका आधारित सुरक्षा का परीक्षण कर रहे हैं , हालांकि आप परीक्षण कर सकते हैं और साथ ही। चलो दो परीक्षण बनाते हैं, एक यह जांचने के लिए कि क्या एक वैध उपयोगकर्ता इस सलामी प्रतिक्रिया को देख सकता है और दूसरा यह जांचने के लिए कि क्या यह वास्तव में निषिद्ध है।@Secured@PreAuthorize@PostAuthorize

@RunWith(SpringRunner.class)
@SpringBootTest(
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
        classes = SpringSecurityWebAuxTestConfig.class
)
@AutoConfigureMockMvc
public class WebApplicationSecurityTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithUserDetails("manager@company.com")
    public void givenManagerUser_whenGetFooSalute_thenOk() throws Exception
    {
        mockMvc.perform(MockMvcRequestBuilders.get("/foo/salute")
                .accept(MediaType.ALL))
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("manager@company.com")));
    }

    @Test
    @WithUserDetails("user@company.com")
    public void givenBasicUser_whenGetFooSalute_thenForbidden() throws Exception
    {
        mockMvc.perform(MockMvcRequestBuilders.get("/foo/salute")
                .accept(MediaType.ALL))
                .andExpect(status().isForbidden());
    }
}

जैसा कि आप देखते हैं कि हमने आयात किया है SpringSecurityWebAuxTestConfig अपने उपयोगकर्ताओं को परीक्षण के लिए प्रदान करने के लिए किया है। हर एक अपने सीधे परीक्षण के मामले पर एक सीधे एनोटेशन का उपयोग करके, कोड और जटिलता को कम करने के लिए इस्तेमाल किया।

बेहतर रोल बेस्ड सिक्योरिटी के लिए @WithMockUser का बेहतर इस्तेमाल करें

जैसा कि आप देखते हैं कि आपके @WithUserDetailsसभी अनुप्रयोगों के लिए आवश्यक सभी लचीलेपन हैं। यह आपको किसी भी GrantedAuthority के साथ कस्टम उपयोगकर्ता का उपयोग करने की अनुमति देता है, जैसे भूमिकाओं या अनुमतियाँ। लेकिन अगर आप केवल भूमिकाओं के साथ काम कर रहे हैं, तो परीक्षण करना और भी आसान हो सकता है और आप एक कस्टम बनाने से बच सकते हैं UserDetailsService। ऐसे मामलों में, उपयोगकर्ता, पासवर्ड और भूमिकाओं के साथ @WithMockUser का एक सरल संयोजन निर्दिष्ट करें ।

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@WithSecurityContext(
    factory = WithMockUserSecurityContextFactory.class
)
public @interface WithMockUser {
    String value() default "user";

    String username() default "";

    String[] roles() default {"USER"};

    String password() default "password";
}

एनोटेशन बहुत मूल उपयोगकर्ता के लिए डिफ़ॉल्ट मानों को परिभाषित करता है। जैसा कि हमारे मामले में जिस मार्ग का हम परीक्षण कर रहे हैं, उसके लिए आवश्यक है कि प्रमाणित उपयोगकर्ता एक प्रबंधक हो, हम इसका उपयोग SpringSecurityWebAuxTestConfigकरना छोड़ सकते हैं और ऐसा कर सकते हैं।

@Test
@WithMockUser(roles = "MANAGER")
public void givenManagerUser_whenGetFooSalute_thenOk() throws Exception
{
    mockMvc.perform(MockMvcRequestBuilders.get("/foo/salute")
            .accept(MediaType.ALL))
            .andExpect(status().isOk())
            .andExpect(content().string(containsString("user")));
}

ध्यान दें कि अब उपयोगकर्ता manager@company.com के बजाय हमें डिफ़ॉल्ट प्रदान कर रहा है @WithMockUser: उपयोगकर्ता ; फिर भी इससे कोई फर्क नहीं पड़ेगा क्योंकि हम वास्तव में उसकी क्या परवाह करते हैं:ROLE_MANAGER

निष्कर्ष

जैसा कि आप एनोटेशन के साथ देखते हैं @WithUserDetailsऔर @WithMockUserहम साधारण परीक्षण करने के लिए हमारे आर्किटेक्चर से अलग कक्षाओं के निर्माण के बिना विभिन्न प्रमाणित उपयोगकर्ता परिदृश्यों के बीच स्विच कर सकते हैं । इसकी भी आपको यह देखने की सलाह दी गई है कि कैसे @WithSecurityContext और भी अधिक लचीलेपन के लिए काम करता है।


कई उपयोगकर्ताओं का मजाक कैसे उड़ाएं ? उदाहरण के लिए, पहला अनुरोध किसके द्वारा भेजा गया है tom, जबकि दूसरा है jerry?
ch271828n

आप एक फ़ंक्शन बना सकते हैं जहां आपका परीक्षण टॉम के साथ है और उसी तर्क के साथ एक और परीक्षण बनाएं और इसे जेरी के साथ परीक्षण करें। प्रत्येक परीक्षण के लिए एक विशेष परिणाम होगा इसलिए अलग-अलग दावे होंगे और यदि कोई परीक्षण विफल होता है तो यह आपको इसके नाम से बताएगा कि किस उपयोगकर्ता / भूमिका ने काम नहीं किया। याद रखें कि एक अनुरोध में उपयोगकर्ता केवल एक ही हो सकता है, इसलिए एक अनुरोध में कई उपयोगकर्ताओं को निर्दिष्ट करने का कोई मतलब नहीं है।
एलियूएक्स

क्षमा करें, मेरा मतलब है कि ऐसा उदाहरण परिदृश्य: हम परीक्षण करते हैं कि, टॉम एक गुप्त लेख बनाता है, फिर जेरी उसे पढ़ने की कोशिश करता है, और जेरी को इसे नहीं देखना चाहिए (क्योंकि यह गुप्त है)। तो इस मामले में, यह एक इकाई परीक्षण है ...
ch271828n

यह उत्तर में दिए गए परिदृश्य BasicUserऔर Manager Userपरिदृश्य की तरह बहुत सुंदर लगता है । मुख्य अवधारणा यह है कि उपयोगकर्ताओं के बारे में परवाह करने के बजाय हम वास्तव में उनकी भूमिकाओं के बारे में परवाह करते हैं, लेकिन उनमें से प्रत्येक परीक्षण, एक ही इकाई परीक्षण में स्थित, वास्तव में विभिन्न प्रश्नों का प्रतिनिधित्व करते हैं। विभिन्न उपयोगकर्ताओं द्वारा (अलग-अलग भूमिकाओं के साथ) एक ही समापन बिंदु पर किया जाता है।
एलियूएक्स

61

स्प्रिंग 4.0+ के बाद से, सबसे अच्छा उपाय है कि @WithMockUser के साथ परीक्षण विधि को एनोटेट करें

@Test
@WithMockUser(username = "user1", password = "pwd", roles = "USER")
public void mytest1() throws Exception {
    mockMvc.perform(get("/someApi"))
        .andExpect(status().isOk());
}

अपनी परियोजना के लिए निम्नलिखित निर्भरता को जोड़ना याद रखें

'org.springframework.security:spring-security-test:4.2.3.RELEASE'

1
वसंत अद्भुत है। धन्यवाद
TuGordoBello

अच्छा उत्तर। इसके अलावा - आपको mockMvc का उपयोग करने की आवश्यकता नहीं है, लेकिन अगर आप इसका उपयोग कर रहे हैं जैसे कि Springframework.data से PagingAndSortingRepository - आप सीधे रिपॉजिटरी से विधियों को कॉल कर सकते हैं (जो EL @PreAuthorize (......) के साथ एनोटेट हैं)
सुपरक्रैम्प

50

यह पता चला कि SecurityContextPersistenceFilterस्प्रिंग सिक्योरिटी फ़िल्टर श्रृंखला का एक हिस्सा है, हमेशा मेरा रीसेट करता है SecurityContext, जिसे मैं कॉलिंग SecurityContextHolder.getContext().setAuthentication(principal)(या .principal(principal)विधि का उपयोग करके ) सेट करता हूं । इस फिल्टर सेट SecurityContextमें SecurityContextHolderएक साथ SecurityContextएक से SecurityContextRepository अधिलेखन एक मैंने पहले निर्धारित किया है। HttpSessionSecurityContextRepositoryडिफ़ॉल्ट रूप से रिपॉजिटरी है । HttpSessionSecurityContextRepositoryदिए गए का निरीक्षण करता है HttpRequestऔर संबंधित को एक्सेस करने की कोशिश करता है HttpSession। यदि यह मौजूद है, इसे पढ़ने के लिए कोशिश करेंगे SecurityContextसे HttpSession। यदि यह विफल रहता है, तो रिपॉजिटरी एक खाली उत्पन्न करता है SecurityContext

इस प्रकार, मेरा समाधान HttpSessionअनुरोध के साथ पारित करना है , जो निम्नलिखित है SecurityContext:

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Test;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;

import eu.ubicon.webapp.test.WebappTestEnvironment;

public class Test extends WebappTestEnvironment {

    public static class MockSecurityContext implements SecurityContext {

        private static final long serialVersionUID = -1386535243513362694L;

        private Authentication authentication;

        public MockSecurityContext(Authentication authentication) {
            this.authentication = authentication;
        }

        @Override
        public Authentication getAuthentication() {
            return this.authentication;
        }

        @Override
        public void setAuthentication(Authentication authentication) {
            this.authentication = authentication;
        }
    }

    @Test
    public void signedIn() throws Exception {

        UsernamePasswordAuthenticationToken principal = 
                this.getPrincipal("test1");

        MockHttpSession session = new MockHttpSession();
        session.setAttribute(
                HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, 
                new MockSecurityContext(principal));


        super.mockMvc
            .perform(
                    get("/api/v1/resource/test")
                    .session(session))
            .andExpect(status().isOk());
    }
}

2
हमने अभी तक स्प्रिंग सुरक्षा के लिए आधिकारिक समर्थन नहीं जोड़ा है। Jira.springsource.org/browse/SEC-2015 देखें कि यह कैसा दिखेगा इसकी रूपरेखा github.com/SpringSource/spring-test-mvc/blob/master/trc/test/…
Rob Winch

मुझे नहीं लगता कि एक प्रमाणीकरण ऑब्जेक्ट बनाना और इसी विशेषता के साथ एक सत्र जोड़ना बुरा है। क्या आपको लगता है कि यह एक मान्य "काम के आसपास" है? दूसरी ओर प्रत्यक्ष समर्थन निश्चित रूप से बहुत अच्छा होगा। बहुत साफ-सुथरा दिखता है। लिंक के लिए धन्यवाद!
मार्टिन बेकर

महान समाधान। मेरे लिए काम किया! संरक्षित पद्धति के नामकरण के साथ सिर्फ एक छोटी सी समस्या है getPrincipal()जो मेरी राय में थोड़ी भ्रामक है। आदर्श रूप से इसका नाम होना चाहिए था getAuthentication()। इसी तरह, आपके signedIn()परीक्षण में, स्थानीय चर का नाम authया authenticationइसके बजाय होना चाहिएprincipal
तनवीर

"GetPrincipal (" test1 ") क्या है? You ?? क्या आप यह बता सकते हैं कि यह कहाँ है? अग्रिम धन्यवाद
user2992476

@ user2992476 यह संभवत: उपयोगकर्ता का एक प्रकार लौटाता है UsernamePasswordAuthenticationToken। वैकल्पिक रूप से, आप GrantedAuthority बनाते हैं और इस ऑब्जेक्ट का निर्माण करते हैं।
ब्ल्युलेरकर

31

Pom.xml में जोड़ें:

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <version>4.0.0.RC2</version>
    </dependency>

और org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessorsप्राधिकरण अनुरोध के लिए उपयोग करें। नमूना उपयोग https://github.com/rwinch/spring-security-test-blog ( https://jira.spring.io/browse/SEC-2592 ) पर देखें

अपडेट करें:

4.0.0.RC2 वसंत-सुरक्षा के लिए काम करता है 3.x. वसंत-सुरक्षा के लिए 4 वसंत-सुरक्षा-परीक्षण वसंत-सुरक्षा ( http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/#test) का हिस्सा बन जाते हैं , संस्करण समान है )।

सेटिंग अप परिवर्तित किया गया है: http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/#test-mockmvc

public void setup() {
    mvc = MockMvcBuilders
            .webAppContextSetup(context)
            .apply(springSecurity())  
            .build();
}

बुनियादी प्रमाणीकरण के लिए नमूना: http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/#testing-http-basic-authication


यह भी एक लॉगिन सुरक्षा फिल्टर के माध्यम से प्रवेश करने की कोशिश कर रहा है जब एक 404 प्राप्त करने के साथ मेरी समस्या तय की। धन्यवाद!
इयान न्यूलैंड

हाय, जबकि GKislin द्वारा उल्लिखित परीक्षण। मैं निम्नलिखित त्रुटि प्राप्त कर रहा हूं "प्रमाणीकरण विफल हो गया UserDetailsService अशक्त लौटा, जो एक इंटरफ़ेस अनुबंध का उल्लंघन है"। कृपया कोई सुझाव। अंतिम ऑथेंटिकेशनरेंसिस्टिक ऑर्टिक = नया ऑथेंटिकेशनRequest (); auth.setUsername (userId); auth.setPassword (पासवर्ड); mockMvc.perform (।। पोस्ट ( "/ API / प्रमाणन /") सामग्री (json (प्रमाणन)) contentType (MediaType.APPLICATION_JSON));
संजीव

7

यहां उन लोगों के लिए एक उदाहरण है जो बेस 64 बुनियादी प्रमाणीकरण का उपयोग करके स्प्रिंग मॉकमेड सिक्योरिटी कॉन्फ़िगरेशन का परीक्षण करना चाहते हैं।

String basicDigestHeaderValue = "Basic " + new String(Base64.encodeBase64(("<username>:<password>").getBytes()));
this.mockMvc.perform(get("</get/url>").header("Authorization", basicDigestHeaderValue).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk());

मावेन निर्भरता

    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.3</version>
    </dependency>

3

संक्षिप्त जवाब:

@Autowired
private WebApplicationContext webApplicationContext;

@Autowired
private Filter springSecurityFilterChain;

@Before
public void setUp() throws Exception {
    final MockHttpServletRequestBuilder defaultRequestBuilder = get("/dummy-path");
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext)
            .defaultRequest(defaultRequestBuilder)
            .alwaysDo(result -> setSessionBackOnRequestBuilder(defaultRequestBuilder, result.getRequest()))
            .apply(springSecurity(springSecurityFilterChain))
            .build();
}

private MockHttpServletRequest setSessionBackOnRequestBuilder(final MockHttpServletRequestBuilder requestBuilder,
                                                             final MockHttpServletRequest request) {
    requestBuilder.session((MockHttpSession) request.getSession());
    return request;
}

formLoginवसंत सुरक्षा परीक्षण से प्रदर्शन के बाद आपके प्रत्येक अनुरोध को स्वचालित रूप से उपयोगकर्ता में लॉग इन कहा जाएगा।

लंबा जवाब:

इस समाधान की जाँच करें (उत्तर वसंत 4 के लिए है): वसंत 3.2 नए mvc परीक्षण के साथ उपयोगकर्ता को कैसे लॉगिन करें


2

परीक्षणों में SecurityContextHolder के उपयोग से बचने के विकल्प:

  • विकल्प 1 : मॉक SecurityContextHolderका उपयोग करें - मेरा मतलब है कि कुछ नकली लाइब्रेरी का उपयोग करके मॉक करें - ईज़ीमॉक उदाहरण के लिए
  • विकल्प 2 : SecurityContextHolder.get...किसी सेवा में अपने कोड में रैप कॉल - उदाहरण के लिए उस SecurityServiceImplविधि के साथ getCurrentPrincipalजिसमें SecurityServiceइंटरफ़ेस लागू होता है और फिर आपके परीक्षणों में आप इस इंटरफ़ेस का नकली कार्यान्वयन बना सकते हैं जो बिना पहुंच के वांछित प्रिंसिपल को वापस कर देता है SecurityContextHolder

Mh, शायद मैं पूरी तस्वीर नहीं मिलता है। मेरी समस्या यह थी कि SecurityContextPersistenceFilter एक SecurityContext का उपयोग करके एक HttpSessionSecurityContextRepository से SecurityContext का उपयोग करता है, जो बदले में इसी HttpSession से SecurityContext को पढ़ता है। इस प्रकार सत्र का उपयोग कर समाधान। SecurityContextHolder पर कॉल के बारे में: मैंने अपना उत्तर संपादित किया ताकि मैं SecurityContextHolder पर कॉल का उपयोग न कर पाऊं। लेकिन बिना किसी रैपिंग या अतिरिक्त मॉकिंग लाइब्रेरी की शुरुआत किए बिना। क्या आपको लगता है, यह एक बेहतर उपाय है?
मार्टिन बेकर

क्षमा करें, मुझे ठीक से समझ में नहीं आया कि आप क्या देख रहे थे और मैं आपके द्वारा दिए गए समाधान से बेहतर उत्तर प्रदान नहीं कर सकता - और यह एक अच्छा विकल्प प्रतीत होता है।
पावला नोवकोव

सब ठीक है, धन्यवाद। मैं अपने प्रस्ताव को अब समाधान के रूप में स्वीकार करूंगा।
मार्टिन बेकर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.