'Integration testing loadUser call on custom OidcUserService in Spring Security

I have the following class that extends OidcUserService:

@Service
public class CustomOidcUserService extends OidcUserService {
    private final UserProfileService profileService;

    public CustomOidcUserService(UserProfileService profileService) {
        this.profileService = profileService;
    }

    @Override
    public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
        var id = UUID.fromString(userRequest.getIdToken().getSubject());
        var preferredUsername = userRequest.getIdToken().getPreferredUsername();

        var profile = profileService.findByUserId(id)
                .orElseGet(() -> profileService.createProfile(id, preferredUsername));

        return new CustomUser(super.loadUser(userRequest), profile);
    }
}

Simple enough so far and it works fine when I run the application, however, I would like to test that this service is indeed working correctly. I've written the following integration test:

@SpringBootTest
class CustomOidcUserServiceTests {
    @MockBean
    private UserProfileService profileService;

    @Autowired
    private WebApplicationContext context;

    private MockMvc mvc;

    @BeforeEach
    public void setup() {
        mvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(springSecurity())
                .build();
    }

    @Test
    public void whenLoadNewUser_createNewProfile() throws Exception {
        when(profileService.findByUserId(any())).thenReturn(Optional.empty());
        when(profileService.createProfile(any(UUID.class), anyString())).thenAnswer(i -> {
            var id = i.getArgument(0, UUID.class);
            var displayName = i.getArgument(1, String.class);
            return new UserProfile(id, displayName);
        });

        mvc.perform(get("/organizations/create")
                .with(oidcLogin().idToken(token -> {
                    token.claim(IdTokenClaimNames.SUB, UUID.randomUUID());
                    token.claim("preferred_username", "testuser");
                })));

        assertThat(mockingDetails(profileService).getInvocations().size()).isEqualTo(2);
    }
}

However, the loadUser method is never called. How can I write a test that calls the loadUser method?



Solution 1:[1]

Have you fixed this issue?

I am working on the same thing, where we have it working in one project but not another.

One thing you haven't posted is your Spring Security configuration. I am assuming you want to use it with Azure AAD. And to do that it is all done in the configuration. Since we can't see it, we can't decode if you have told Spring you want to use your custom class. Here is an example of how we used our custom one.

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class AADOAuth2LoginSecurityConfig extends AADWebSecurityConfigurerAdapter {

@Resource
OAuth2UserService<OidcUserRequest, OidcUser> customOidcUserService;

@Override
protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http
            .authorizeRequests()
            .antMatchers("/", "/login", "/*.js", "/*.css").permitAll()
            .anyRequest().authenticated()
            .and()
            .csrf()
            .disable()
            .oauth2Login(oauth2Login ->
                    oauth2Login.userInfoEndpoint(userInfoEndpoint ->
                            userInfoEndpoint.oidcUserService(customOidcUserService)
                    )
            );
}

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 user1567291