Coder Social home page Coder Social logo

Comments (5)

ch4mpy avatar ch4mpy commented on June 13, 2024

Hi @schmitzhermes and thank you for this detailed issue report.

You are right, it seems that resource access mapping is missing just where you spotted. Will fix asap.

As a side note, you shouldn't define authorities twice. Define it either in authorities or in private claims.
If your application code just check authorities with standard SpEL (hasAuthority, hasRole, etc.), first option is clearly the easiest, less verbose and most readable way (and it already works).
The second option is only necessary if your application code explicitely accesses KeycloakRessourceAccess, which I personaly discourage as it makes it strongly adherent to Keycloak (migrating to another OIDC authorization server would be painful).

from spring-addons.

ch4mpy avatar ch4mpy commented on June 13, 2024

There is a pitfall with htis feature: to my understanding, keycloak lib only adds to authorities the roles from a single resource access (the one configured with keycloak.resource property). This perfectly logical as we are writing and testing the code for this specific resource-server...
I don't have in mind a good way to retrieve such a config property during the tests right now and would rather map all roles from all resource-accesses: if you don't want it in the test security context, don't put it in the test annotation.

But, again, this unit (not integration) testing and roles parsing doesn't involve application authorities mappers (which can do about anything like adding prefix, modifying case, append stuff, or even add or ignore roles) and configuring authorities with already parsed roles should be the prefered way.

Here is the modified test for the solution I propose:

	// @formatter:off
	@Test
	@WithMockKeycloakAuth(
			authorities = {"USER", "AUTHORIZED_PERSONNEL" },
			claims = @OpenIdClaims(
					sub = "42",
					jti = "123-456-789",
					nbf = "2020-11-18T20:38:00Z",
					sessionState = "987-654-321",
					email = "[email protected]",
					emailVerified = true,
					nickName = "Tonton-Pirate",
					preferredUsername = "ch4mpy",
					otherClaims = @Claims(jsonObjectClaims = @JsonObjectClaim(name = "foo", value = OTHER_CLAIMS))),
			accessToken = @KeycloakAccessToken(
					realmAccess = @KeycloakAccess(roles = { "TESTER" }),
					authorization = @KeycloakAuthorization(permissions = @KeycloakPermission(rsid = "toto", rsname = "truc", scopes = "abracadabra")),
					resourceAccess = {
							@KeycloakResourceAccess(resourceId = "resourceA", access = @KeycloakAccess(roles = {"A_TESTER"})),
							@KeycloakResourceAccess(resourceId = "resourceB", access = @KeycloakAccess(roles = {"B_TESTER"}))}))
	// @formatter:on
	public void whenAuthenticatedWithKeycloakAuthenticationTokenThenCanGreet() throws Exception {
		api
				.get("/greet")
				.andExpect(status().isOk())
				.andExpect(content().string(startsWith("Hello ch4mpy! You are granted with ")))
				.andExpect(content().string(containsString("AUTHORIZED_PERSONNEL")))
				.andExpect(content().string(containsString("USER")))
				.andExpect(content().string(containsString("TESTER")))
				.andExpect(content().string(containsString("A_TESTER")))
				.andExpect(content().string(containsString("B_TESTER")));
	}

Maybe what you need in your test is somthing like (note the ROLE_ prefix in authorities but not in realm / resource accesses):

	// @formatter:off
	@Test
	@WithMockKeycloakAuth(
			authorities = {"ROLE_TESTER", "ROLE_A_TESTER" }, // or {"ROLE_TESTER", "ROLE_B_TESTER" }
			claims = @OpenIdClaims(
					sub = "42",
					jti = "123-456-789",
					nbf = "2020-11-18T20:38:00Z",
					sessionState = "987-654-321",
					email = "[email protected]",
					emailVerified = true,
					nickName = "Tonton-Pirate",
					preferredUsername = "ch4mpy",
					otherClaims = @Claims(jsonObjectClaims = @JsonObjectClaim(name = "foo", value = OTHER_CLAIMS))),
			accessToken = @KeycloakAccessToken(
					realmAccess = @KeycloakAccess(roles = { "TESTER" }),
					authorization = @KeycloakAuthorization(permissions = @KeycloakPermission(rsid = "toto", rsname = "truc", scopes = "abracadabra")),
					resourceAccess = {
							@KeycloakResourceAccess(resourceId = "resourceA", access = @KeycloakAccess(roles = {"A_TESTER"})),
							@KeycloakResourceAccess(resourceId = "resourceB", access = @KeycloakAccess(roles = {"B_TESTER"}))}))
	// @formatter:on
	public void whenAuthenticatedWithKeycloakAuthenticationTokenThenCanGreet() throws Exception {
		api
				.get("/greet")
				.andExpect(status().isOk())
				.andExpect(content().string(startsWith("Hello ch4mpy! You are granted with ")))
				.andExpect(content().string(containsString("ROLE_TESTER")))
				.andExpect(content().string(containsString("ROLE_A_TESTER")))
				.andExpect(content().string(containsString("TESTER")))
				.andExpect(content().string(containsString("A_TESTER")))
				.andExpect(content().string(containsString("B_TESTER")));
	}

from spring-addons.

ch4mpy avatar ch4mpy commented on June 13, 2024

fixed in 3.1.14 (release ongoing). Please, @schmitzhermes close if you can confirm issue is solved.

from spring-addons.

schmitzhermes avatar schmitzhermes commented on June 13, 2024

It works just fine - thank you.
One remark: the 3.1.14-jdk1.8 does not seem to be on maven central yet. Is this just a timing thing or do u need to deploy that manually?

from spring-addons.

ch4mpy avatar ch4mpy commented on June 13, 2024

I can see it on https://repo1.maven.org/maven2/com/c4-soft/springaddons/spring-security-oauth2-addons/

I deploy to sonatype which handles deployment to repo1.maven.org (this rarely takes more than 2 hours)

from spring-addons.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.