Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for parametrized OAuth2 Authentications in @ParameterizedTest #122

Closed
thekalinga opened this issue Jun 11, 2023 · 3 comments
Closed
Assignees
Labels
enhancement New feature or request

Comments

@thekalinga
Copy link

thekalinga commented Jun 11, 2023

Is your feature request related to a problem? Please describe.

If an endpoint is accessible to users with multiple authorities, I have to create one test per role and put same annotations on each of them method except authority.

@Test
@WithMockJwtAuth(authorities = {"role1"})
void secureEndpoint_Scenario() {
....
}

@Test
@WithMockJwtAuth(authorities = {"role2"})
void secureEndpoint_Scenario() {
....
}

@Test
@WithMockJwtAuth(authorities = {"role3"})
void secureEndpoint_Scenario() {
....

Describe the solution you'd like

I would want to use junit's ParameterizedTest to pass this information

@ParameterizedTest
@ValueSource(strings = {"role1", "role2", "role3"})
@WithMockJwtAuth(authorities = <build custom Security Context with Jwt Auth referring to value source>)
void secureEndpoint_Scenario() {
....
}

Describe alternatives you've considered
None as I am still a noob with this framework.

@thekalinga thekalinga added the enhancement New feature or request label Jun 11, 2023
@thekalinga thekalinga changed the title Add support for @WithMockJwtAuth with the ability to change roles using @ParameterizedTest Add support for @WithMockJwtAuth with the ability to change authorities using @ParameterizedTest Jun 11, 2023
@thekalinga thekalinga changed the title Add support for @WithMockJwtAuth with the ability to change authorities using @ParameterizedTest Support for @WithMockJwtAuth with ability to change authorities using @ParameterizedTest Jun 11, 2023
@ch4mpy
Copy link
Owner

ch4mpy commented Jun 13, 2023

I'm not sure that what you ask is possible: as per its name, @ParameterizedTest parameterizes the test itself, not its annotations. When the test instance is called with parameters, the security context has already been populated by @WithMockJwtAuth and I know no hook in WithSecurityContextFactory to read @ParameterizedTest value.

If you only test @Controller security (not a @Service or other @Component), what you can already do is use MockMvc request post-processor or WebTestClient mutator:

@ParameterizedTest
@ValueSource(strings = { "NICE", "VERY_NICE" })
void givenUserIsGrantedWithAnyNiceAuthority_whenGetRestricted_thenOk(String authority) throws Exception {
    api.perform(get("/restricted").with(SecurityMockMvcRequestPostProcessors.jwt().authorities(new SimpleGrantedAuthority(authority))))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.body").value("You are so nice!"));
}

I will investigate how complicated it would be to write an equivalent of @ValueSource for Authentication instances. Something like @JwtAuthenticationSource(auths = { @WithMockJwtAuth("role1"), @WithMockJwtAuth("role2") }) which would instantiate a JwtAuthenticationToken for each entry, populate the test security context with it and then pass it as an argument to the test function

@ch4mpy
Copy link
Owner

ch4mpy commented Jun 13, 2023

Here is what I came to so far:

@ParameterizedTest
@JwtAuthenticationSource({ @WithMockJwtAuth(authorities = "NICE"), @WithMockJwtAuth(authorities = "VERY_NICE") })
void givenUserIsGrantedWithAnyNiceAuthentication_whenGetRestricted_thenOk(@JwtAuth JwtAuthenticationToken auth) throws Exception {
	api.perform(get("/restricted"))
			.andExpect(status().isOk())
			.andExpect(jsonPath("$.body").value("You are so nice!"));
}

Mind the @JwtAuthenticationSource decorating the test method and the @JwtAuth decorating the variable argument. Both are required:

  • @JwtAuthenticationSource defines the different authentications to build for each test
  • @JwtAuth inserts the current authentication in the security context

@thekalinga what do you think of this solution?

This relies on the following:

@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@ArgumentsSource(JwtAuthenticationSource.JwtAuthenticationsProvider.class)
public @interface JwtAuthenticationSource {
	WithMockJwtAuth[] value() default {};

	static class JwtAuthenticationsProvider implements ArgumentsProvider, AnnotationConsumer<JwtAuthenticationSource> {
		private final WithMockJwtAuth.JwtAuthenticationTokenFactory authFactory = new WithMockJwtAuth.JwtAuthenticationTokenFactory();

		private Collection<JwtAuthenticationToken> arguments;

		@Override
		public void accept(JwtAuthenticationSource source) {
			// @formatter:off
			arguments =
					Stream.of(source.value())
					.map(authFactory::authentication)
					.toList();
		}

		@Override
		public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
			return arguments.stream().map(Arguments::of);
		}

	}
}
public class JwtAuthenticationArgumentProcessor extends TypedArgumentConverter<JwtAuthenticationToken, JwtAuthenticationToken> {

	protected JwtAuthenticationArgumentProcessor() {
		super(JwtAuthenticationToken.class, JwtAuthenticationToken.class);
	}

	@Override
	protected JwtAuthenticationToken convert(JwtAuthenticationToken source) {
		SecurityContextHolder.getContext().setAuthentication(source);

		return source;
	}

}
@Target({ ElementType.ANNOTATION_TYPE, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@ConvertWith(JwtAuthenticationArgumentProcessor.class)
public @interface JwtAuth {
}

@ch4mpy ch4mpy changed the title Support for @WithMockJwtAuth with ability to change authorities using @ParameterizedTest Support for parametrized OAuth2 Authentications for @ParameterizedTest Jun 14, 2023
@ch4mpy ch4mpy changed the title Support for parametrized OAuth2 Authentications for @ParameterizedTest Support for parametrized OAuth2 Authentications in @ParameterizedTest Jun 14, 2023
@ch4mpy
Copy link
Owner

ch4mpy commented Jun 14, 2023

Released in 6.1.12. See release notes for usage details.

@ch4mpy ch4mpy closed this as completed Jun 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants