AccessDeniedException when implements HasDynamicTitle and @RolesAllowed("ROLE_ADMIN")

Hi,

I am using Vaadin v23, Spring Boot and Spring Security.

I have a view restricted with @RolesAllowed("ROLE_ADMIN"). The view implements HasDynamicTitle.

This results in a AccessDeniedException. The log contains a security related message saying this:

Failed to authorize ReflectiveMEthodInvocation.... AdminView.getPageTitle() ...... and decision AuthorityAuthorizationDecision [granted=false, authorities=[ROLE_ROLE_ADMIN]]

Note the ROLE_ROLE_ prefix which clearly is why this will not work.

Removing implements HasDynamicTitle solves the problem. We obviously lack regression testing which could have caught this, but at the same time I can confirm this have worked previously like when first implemented. The application is under development and ADMIN was just an example. I just found this error by coincidence.

Spring security works as intended elsewhere.

Is this a known bug or Is this a problem only I have?

I have no source to share as this application is developed on-premise without access to internet. If I have to I can create a project which isolates the problem and then share but I hope that will not be necessary.

Sounds like a new bug; I couldn’t see anything matching this on Issues · vaadin/flow · GitHub at a quick glance. Please create a new issue.

My first guess is that the problem could be related to Spring Method Security, rather than Flow.

Adding the HasDynamicTitle interface on Flow test module for method security works without any error.
To be noted that on the test view we have the @RolesAllowed annotation no using the ROLE_ prefix.
And actually Spring Jsr250AuthorizationManager is adding the hard-code ROLE_ prefix when doing its login

		private Set<String> getAllowedRolesWithPrefix(RolesAllowed rolesAllowed) {
			Set<String> roles = new HashSet<>();
			for (int i = 0; i < rolesAllowed.value().length; i++) {
				roles.add(Jsr250AuthorizationManager.this.rolePrefix + rolesAllowed.value()[i]);
			}
			return roles;
		}

@Marco I think you addressed the correct problem.

I just found this which confirm the fact and clearly shows the differences since

I have @EnableMethodSecurity(jsr250Enabled = true), however @EnableGlobalMethodSecurity is deprecated since Spring Security 3.0 and therefor not an option, so I guess I just have to remove ROLE_ all over. I will try that.

I’m sorry. I posted code from Spring Security 6 (Spring Boot 3) instead of checking Spring Security 5 (Spring Boot 2.7) that should be in use with Vaadin 23.
Anyway in Spring Security 5 I can see something similar in JSR 250 authorization manager logic

	private static String[] toNamedRolesArray(String rolePrefix, String[] roles) {
		String[] result = new String[roles.length];
		for (int i = 0; i < roles.length; i++) {
			String role = roles[i];
			Assert.isTrue(!role.startsWith(rolePrefix), () -> role + " should not start with " + rolePrefix + " since "
					+ rolePrefix
					+ " is automatically prepended when using hasAnyRole. Consider using hasAnyAuthority instead.");
			result[i] = rolePrefix + role;
		}
		return result;
	}

So it definitely seems that the ROLE_ prefix should not be present in the security annotation.

Removing ROLE_ from @RolesAllowed("ROLE_ADMIN") and continue use the annotation @EnableMethodSecurity(jsr250Enabled=true) as is, seems to be working.

My guess is that this change resulting in AccessDeniedException came with Spring Boot 3.0 upgrade a while back. It’s just speculation and will not go back in time to explore this further. It is something Vaadin maybe should address in the merging documentation regarding Spring since this could be an issue for other developers.

Thanks @Marco for pointing me in the right direction. Also seeing your last post I am using Spring Security 6.2.3.

Spring Security v5 at least warned about the ROLE_ issue which v6 does not seem to do.

I see now that the fault is all mine.

In February I ran a OpenWrite for Spring Boot 3.2 upgrade. And I now see that @EnableGlobalMethodSecurity was replaced with @EnableMethodSecurity.

That’s when the problem was introduced. Very sorry for even thinking Vaadin could maybe be the culprit for what I obviously did myself with some help from OpenWrite (dangerous thinking that would go just fine).

No worries :smile:
It is good to know what the cause of the issue was.

1 Like