Maxdola
Maxdola

Reputation: 1650

Spring Boot AccessDecisionVoter custom Unauthorized message

I have a custom AccessDecisionVoter for a custom Annotation, which restricts the access to certain methods, based on the scopes provided in the Annotation. This works without a problem, but the response I get when the Authentication is missing the scope is always the same and I am looking for a way to customize this. Thank you in advance.

ScopeVoter

public class ScopeVoter implements AccessDecisionVoter<MethodInvocation> {

    @Override
    public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
        //custom logic here which decides to grant or deny the access. Here the message should be customized.
    }

AuthenticationEntryPoint

@Component
public class AuthenticationEntryPointImp implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }
}

This is where the response is generated and I am trying to get the custom message to this AuthenticationEntryPoint.

HTTPSecurety Configuration

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable()
            .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint()).and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests().antMatchers("/auth/**").permitAll()
            .anyRequest().authenticated();

    http.addFilterBefore(authFilter(), UsernamePasswordAuthenticationFilter.class);
}

authenticationEntryPoint() is the described class above.

PS: I also want to get a custom message from the authFilter() to the EntryPoint.

EDIT: It was pointed out to me that this might not be possible, but if not in the AuthenticationEntryPoint there must be another place. And I also want to display a custom message from the AuthenticationFilter in the AuthenticationEntryPoint, which definitely gets called when the auth fails.

Upvotes: 0

Views: 645

Answers (3)

clevertension
clevertension

Reputation: 7077

if use is authenticated successfully, and then the voter is denied, you can configure your AccessDeniedHandler

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
                .exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
                @Override
                public void handle(HttpServletRequest request, HttpServletResponse response,
                        AccessDeniedException accessDeniedException) throws IOException, ServletException {
                    response.getWriter().println(accessDeniedException.getMessage());
                }
            }).authenticationEntryPoint(authenticationEntryPoint()).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests().antMatchers("/auth/**").permitAll()
                .anyRequest().authenticated();
    
        http.addFilterBefore(authFilter(), UsernamePasswordAuthenticationFilter.class);
    }

then in ScopeVoter, you can throw AccessDeniedException by yourself

public class ScopeVoter implements AccessDecisionVoter<MethodInvocation> {

@Override
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
    //if the logic is not met, throw it directly
    throw new AccessDeniedException("your customize message is here");
}

Upvotes: 1

Peter Nagy
Peter Nagy

Reputation: 158

For the customized error response part of your question: I have configured CustomAuthenticationEntryPoint so that it invokes my general exception handler defined with @ControllerAdvice.

@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException, ServletException {
        resolver.resolveException(request, response, null, ex);
    }
}

Source code is available here.

Upvotes: 1

clevertension
clevertension

Reputation: 7077

enter image description here

I think it is impossible to do this, because AuthenticationEntryPoint.commence() and AccessDecisionVoter.voter() is mutual exclusion, when the authentication is failure, the voter will not be called, when the authentication is success, the commence will not be called()

Upvotes: 1

Related Questions