web-dev-qa-db-fra.com

Comment désactiver la sécurité de printemps pour une URL particulière

J'utilise la sécurité de printemps sans état, mais en cas d'inscription, je souhaite désactiver la sécurité de printemps. J'ai désactivé l'utilisation de 

antMatchers("/api/v1/signup").permitAll().

mais cela ne fonctionne pas, je reçois une erreur ci-dessous: 

 message=An Authentication object was not found in the SecurityContext, type=org.springframework.security.authentication.AuthenticationCredentialsNotFoundException

Je pense que cela signifie que les filtres de sécurité à ressort fonctionnent

L'ordre de mon URL sera toujours "/ api/v1"

Ma config de printemps est

@Override
    protected void configure(HttpSecurity http) throws Exception {

         http.
         csrf().disable().
         sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).
         and().
         authorizeRequests().
         antMatchers("/api/v1/signup").permitAll().
         anyRequest().authenticated().
         and().
         anonymous().disable();
        http.addFilterBefore(new AuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class);
    }

Mon filtre d'authentification est

@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = asHttp(request);
        HttpServletResponse httpResponse = asHttp(response);

        String username = httpRequest.getHeader("X-Auth-Username");
        String password = httpRequest.getHeader("X-Auth-Password");
        String token = httpRequest.getHeader("X-Auth-Token");

        String resourcePath = new UrlPathHelper().getPathWithinApplication(httpRequest);

        try {

            if (postToAuthenticate(httpRequest, resourcePath)) {            
                processUsernamePasswordAuthentication(httpResponse, username, password);
                return;
            }

            if(token != null){
                processTokenAuthentication(token);
            }
            chain.doFilter(request, response);
        } catch (InternalAuthenticationServiceException internalAuthenticationServiceException) {
            SecurityContextHolder.clearContext();
            logger.error("Internal authentication service exception", internalAuthenticationServiceException);
            httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } catch (AuthenticationException authenticationException) {
            SecurityContextHolder.clearContext();
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
        } finally {
        }
    }

     private HttpServletRequest asHttp(ServletRequest request) {
            return (HttpServletRequest) request;
        }

        private HttpServletResponse asHttp(ServletResponse response) {
            return (HttpServletResponse) response;
        }

        private boolean postToAuthenticate(HttpServletRequest httpRequest, String resourcePath) {
            return Constant.AUTHENTICATE_URL.equalsIgnoreCase(resourcePath) && httpRequest.getMethod().equals("POST");
        }

        private void processUsernamePasswordAuthentication(HttpServletResponse httpResponse,String username, String password) throws IOException {
            Authentication resultOfAuthentication = tryToAuthenticateWithUsernameAndPassword(username, password);
            SecurityContextHolder.getContext().setAuthentication(resultOfAuthentication);
            httpResponse.setStatus(HttpServletResponse.SC_OK);
            httpResponse.addHeader("Content-Type", "application/json");
            httpResponse.addHeader("X-Auth-Token", resultOfAuthentication.getDetails().toString());
        }

        private Authentication tryToAuthenticateWithUsernameAndPassword(String username,String password) {
            UsernamePasswordAuthenticationToken requestAuthentication = new UsernamePasswordAuthenticationToken(username, password);
            return tryToAuthenticate(requestAuthentication);
        }

        private void processTokenAuthentication(String token) {
            Authentication resultOfAuthentication = tryToAuthenticateWithToken(token);
            SecurityContextHolder.getContext().setAuthentication(resultOfAuthentication);
        }

        private Authentication tryToAuthenticateWithToken(String token) {
            PreAuthenticatedAuthenticationToken requestAuthentication = new PreAuthenticatedAuthenticationToken(token, null);
            return tryToAuthenticate(requestAuthentication);
        }

        private Authentication tryToAuthenticate(Authentication requestAuthentication) {
            Authentication responseAuthentication = authenticationManager.authenticate(requestAuthentication);
            if (responseAuthentication == null || !responseAuthentication.isAuthenticated()) {
                throw new InternalAuthenticationServiceException("Unable to authenticate Domain User for provided credentials");
            }
            logger.debug("User successfully authenticated");
            return responseAuthentication;
        }

Mon contrôleur est 

@RestController
public class UserController {

    @Autowired
    UserService userService;

    /**
     * to pass user info to service
     */
    @RequestMapping(value = "api/v1/signup",method = RequestMethod.POST)
    public String saveUser(@RequestBody User user) {
        userService.saveUser(user);
        return "User registerted successfully";
    }
}

Je suis totalement nouveau au printemps, aidez-moi s'il vous plaît comment le faire?

51
Prabjot Singh

Lorsque vous utilisez permitAll, cela signifie tous les utilisateurs authentifiés. Cependant, vous avez désactivé l'accès anonyme pour que cela ne fonctionne pas. 

Ce que vous voulez, c'est ignorer certaines URL pour cette substitution. Redéfinissez la méthode configure qui utilise l'objet WebSecurity et le motif ignore.

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/api/v1/signup");
}

Et supprimez cette ligne de la partie HttpSecurity. Cela indiquera à Spring Security d'ignorer cette URL et de ne leur appliquer aucun filtre.

96
M. Deinum

J'ai un meilleur moyen:

http
    .authorizeRequests()
    .antMatchers("/api/v1/signup/**").permitAll()
    .anyRequest().authenticated()
9
javajoker
<http pattern="/resources/**" security="none"/>

Ou avec la configuration Java:

web.ignoring().antMatchers("/resources/**");

Au lieu de l'ancien:

 <intercept-url pattern="/resources/**" filters="none"/>

pour exp. désactiver la sécurité pour une page de connexion:

  <intercept-url pattern="/login*" filters="none" />
7
Sagar Bhandari

Ce n'est peut-être pas la réponse complète à votre question, mais si vous cherchez un moyen de désactiver la protection CSRF, vous pouvez le faire

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/web/admin/**").hasAnyRole(ADMIN.toString(), GUEST.toString())
                .anyRequest().permitAll()
                .and()
                .formLogin().loginPage("/web/login").permitAll()
                .and()
                .csrf().ignoringAntMatchers("/contact-email")
                .and()
                .logout().logoutUrl("/web/logout").logoutSuccessUrl("/web/").permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin").password("admin").roles(ADMIN.toString())
                .and()
                .withUser("guest").password("guest").roles(GUEST.toString());
    }

}

J'ai inclus la configuration complète mais la ligne de clé est la suivante: 

.csrf().ignoringAntMatchers("/contact-email")
4
Tomasz Mularczyk

Comme @ M.Deinum a déjà écrit la réponse. 

J'ai essayé avec api /api/v1/signup. cela contournera le filtre/filtre personnalisé, mais une requête supplémentaire invoquée par le navigateur pour /favicon.ico, aussi, j'ajoute cela aussi dans web.ignoring () et cela fonctionne pour moi.

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/api/v1/signup", "/favicon.ico");
}

Peut-être que ce n'est pas nécessaire pour la question ci-dessus.

0
eigenharsha