Closed schmitzhermes closed 2 years ago
@schmitzhermes I am a little confused with htis one :/
This is something I'm using all the time (injected authentication in controllers methods) and it works like a charm...
Did you forget to add @WithMockKeycloakAuth
when you got the NPE? or maybe did you try to cast to a wrong authentication impl? (but you'd have had soemthing else than NPE, I guess...)
I added explicit tests for what I understand your use-case is (see the linked commit just above). Do not easitate to open a PR with some more tests if I missunderstood what you're trying to do (or close this issue if there is no problem in the end)
Hmm your tests in 61a5d look pretty much like what I am doing... the thing is: it's not the first time I hit this issue, just this time I invested some time to investigate further. Maybe a good next step would be to set up a vanilla setup on my side and see whether it works there or not.
Maybe one thing to understand the issue a little better: If you debug the session and you set a breakpoint in the ServletRequestMethodArgumentResolver
on the respective line. What is the type of the request
object in your setup? Is it a MockHttpServletRequest
as well?
Here is the request.getClass()
output: class org.springframework.security.web.servletapi.HttpServlet3RequestFactory$Servlet3SecurityContextHolderAwareRequestWrapper
But spring-security-tests should ensure that, inside @WebMvcTest
, all MockMvc requests are populated with TestSecurityContext
content (whatever the actual request implementation it chooses...)
That reminds me of an other check: are your failing tests decorated with @WebMvcTest
?
class org.springframework.security.web.servletapi.HttpServlet3RequestFactory$Servlet3SecurityContextHolderAwareRequestWrapper
That's the crucial difference then, since the SecurityContextAwareRequestWrapper
sets the principal based on the SecurityContext
.
That reminds me of an other check: are your failing tests decorated with @WebMvcTest?
No, they are decorated with @SpringBootTest
and @AutoConfigureMockMvc
... this seems to be the difference then, hm?
Maybe security config is missing in the test configuration you import?
Did you have to @MockBean JwtDecoder jwtDecoder
for the tests to pass with Keycloak down?
If you set a breakpoint in some security bean factory, do you hit it?
The test pass if I replace @WebMvcTest
with @SpringBootTest
:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
@Import({ ServletKeycloakAuthUnitTestingSupport.UnitTestConfig.class, KeycloakSpringBootSampleApp.KeycloakConfig.class })
// because this sample stands in the middle of non spring-boot-keycloak projects, keycloakproperties are isolated in
// application-keycloak.properties
@ActiveProfiles("keycloak")
public class GreetingControllerAnnotatedTest {
...
}
Which webEnvironment
are you using?
Do you import Keycloak conf?
@schmitzhermes I can't reproduce and need more feedback.
For now, I believe in test misconfiguration, reason for closing. Please re-open if I'm wrong.
Fine. For now I accepted the solution to specify the principal manually, I will let you know when I had time to investigate the issue further. Thanks for ur support
Describe the bug First of all - thanks for your amazing work!
This is a bit of a tricky issue, so I try to be concise:
authentication
in theSecurityContext
is set just fineAuthentication
/Principal
object into the resource method in the controller does not work, as this object is always nullServletRequestMethodArgumentResolver
tries to set theauthentication
parameter by using theuserPrincipal
of theHttpServletRequest
SecurityContextHolderAwareRequestWrapper
is used in production and this delegates to theSecurityContext
in order to retrieve theuserPrincipal
(see SecurityContextHolderAwareRequestWrapper#123)MockHttpServletRequest
, which does not delegate to theSecurityContext
, but expects theuserPrincipal
to be set explicitly (see: MockHttpServletRequest#1230authentication
parameter being nullCode sample Controller Code:
Test Code
Expected behavior Expected: The
authentication
parameter is not null and contains the configuredKeycloakAuthenticationToken
object. Actual: Theauthentication
parameter is null and leads to aNPE
.Additional context There is a workaround by setting the
principal
explicitly (using theAuthentication
object in theSecurityContext
but this feels wrong. Full working test: