Expected Behavior

You should be able to internationalize the org.springframework.security.access.AccessDeniedException message in any place it is used.

Current Behavior

For now, the only place where the message can be internationalized is in the AccessDecisionMangagers (org.springframework.security.access.vote.AffirmativeBased, org.springframework.security.access.vote.ConsensusBased and org.springframework.security.access.vote.UnanimousBased) as all extend org.springframework.security.access.vote.AbstractAccessDecisionManager which has a org.springframework.context.support.MessageSourceAccesor and calls messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied") to get the message.

org.springframework.security.access.expression.method.ExpressionBasedPostInvocationAdvice, org.springframework.security.access.prepost.PrePostAdviceReactiveMethodInterceptor, org.springframework.security.authorization.ReactiveAuthorizationManager, org.springframework.security.provisioning.InMemoryUserDetailsManager and org.springframework.security.provisioning.JdbcUserDetailsManager create new org.springframework.security.access.AuthorizationServiceException with hard-coded messages.

They should use the same org.springframework.context.support.MessageSourceAccesor mechanism that org.springframework.security.access.vote.AbstractAccessDecisionManager is using to allow i18n.

The same with org.springframework.security.access.vote.AbstractAclVoter (as it creates a new org.springframework.security.access.AuthorizationServiceException -that extends org.springframework.security.access.AccessDeniedException- with hard-coded message).

Also with org.springframework.security.web.server.csrf.CsrfWebFilter, org.springframework.security.web.csrf.MissingCsrfTokenException and org.springframework.security.web.csrf.InvalidCsrfTokenException (create or extend org.springframework.security.web.csrf.CsrfException -that extends org.springframework.security.access.AccessDeniedException- with hard-coded message).

And, finally, org.springframework.security.web.server.csrf.CsrfWebFilter (as it creates a new org.springframework.security.web.server.csrf.CsrfException -that extends org.springframework.security.access.AccessDeniedException- with hard-coded message).

Context

I'm trying to fully internationalize my application (and Exception messages are part of that) but looks like most Exceptions have hard-coded messages and that almost nobody uses things like e.getLocalizedMessage() cause there is almost no support for that (most of the times this method only delegates to e.getMessage())

PS: It would be great if any Spring Exception could extend a base Exception with localization support so you don't need to be aware of the MessageSourceAccesor or anything like that (but be aware of provide the message key and parameters for the message, in case those are required)

Comment From: marcusdacoregio

Hi @rubensa, thanks for the report. Would you like to work on this enhancement?

Comment From: rubensa

I'd like but have no time for now, sorry :(

Comment From: sjohnr

No problem @rubensa.

I think this would be a very worthwhile enhancement that someone in the community could work on. One possible approach might be:

  • Enhance AccessDeniedException to accept a localization key and default message
  • Override Throwable#getLocalizedMessage to make use of MessageSourceAccessor to look up a translation (if available)
  • Use e.getLocalizedMessage() where applicable in the framework
  • Optional: Add the same support for other Spring Security exceptions (as separate enhancements)

If you're interested in working on this issue, let us know! As always, you can use this issue to discuss potential solutions and ideas prior to submitting a PR.

Comment From: dkodippily

@sjohnr can I work on this ?

Comment From: sjohnr

Absolutely, @dkodippily. If you have any thoughts leading into the work, feel free to share and we can discuss it.

Comment From: dkodippily

Thanks @sjohnr, at this stage is it a case-by-case fix? I mean clearly we can add support for AccessDeniedException as you also have pointed, what about other Exception classes ? Any thoughts would be appreciated.

Comment From: sjohnr

@dkodippily, I think we have to start with one or more experiments, to see if there's a direction we can take that a) works consistently and b) does not cause any new problems.

So I'm thinking with this issue we would indeed start with AccessDeniedException, and keep the solution encapsulated for now so we can easily evolve and expand it in the future (assuming it's the right solution for this case). We can start by changing AccessDeniedException itself and overriding getLocalizedMessage().

If that does not work, we can fall back to a more case-by-case basis in areas that use this exception and see if MessageSourceAware or some other mechanism can help.

Comment From: dkodippily

@sjohnr I have created a PR but unfortunately just realised the build is failing due to a Test, strange enough locally all testes are green and branch builds fine. For the Tests I'm reading the newly added message keys from the org.springframework.security Resource bundle. Since we are using the SpringSecurityMessageSource it says "Therefore this class is only used when the deployment environment has not specified an alternative message source." will this be an issue with regards to this specific test Fail, trying to understand as all tests are green and builds fine when running the local branch.

Comment From: dkodippily

10113

@sjohnr I fixed the failing tests , PR is updated.