Reputation: 1
This is the block of code integration test, where the HttpClientErrorException$Unauthorized: 401
error occurs. The problem occurs in the line this.session = stompClient.connect(...)
when creating the session. URL and port is TRUE.
@BeforeEach
@Transactional
void init() throws Exception {
WebSocketStompClient stompClient = new WebSocketStompClient(new SockJsClient(
Collections.singletonList(new WebSocketTransport(new StandardWebSocketClient()))));
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
this.session = stompClient.connect(
WEBSOCKET_URL.formatted(port),
new StompSessionHandlerAdapter() {
}).get(1, SECONDS);
In our project, authentication occurs via a token.
But for example, almost all integration tests on REST endpoints work without authentication, there is one REST test in which authentication is written - in Security Context, an Authentication object is passed with a set "test" token (described in OAuth2TestUtil).
I tried to set the Authentication object in the Web Socket test in the Security Context - but it did not help. Below is an example of code on how Authentication was set in the integration REST test:
@Test
@Transactional
void testIsTrainedEntityNotFoundException() {
userRepository.saveAndFlush(user);
TestSecurityContextHolder.getContext()
.setAuthentication(OAuth2TestUtil.registerAuthenticationToken(authorizedClientService, clientRegistration,
OAuth2TestUtil.authenticationToken(new HashMap<>())));
Exception exception = Assertions.assertThrows(EntityNotFoundException.class, () -> userService.isTrained());
String expectedMessage = "User with login";
String actualMessage = exception.getMessage();
assertTrue(actualMessage.contains(expectedMessage));
userRepository.delete(user);
}
OAuth2TestUtil described at the end of the article
Below is the full test code
/**
* Test for {@link ArticleBlockWebsocket}.
*/
@WithMockUser(username = TestUtil.DEFAULT_ADMIN)
@IntegrationTest
@AutoConfigureMockMvc
class ArticleBlockWebsocketIT {
private static final String ARTICLE_CREATE_URL = "/api/spaces/{spaceId}/articles";
private static final String ARTICLE_GET_URL = "/api/articles/{articleId}";
private static final String SPACE_CREATE_URL = "/api/spaces";
private static final String WEBSOCKET_URL = "ws://localhost:%d/websocket/tracker";
private static final String TOPIC = "/topic";
private static final String KERNEL = "/kernel";
private static final String ADD_URL = "%s/articles/%d/block/add-after";
private static final String EDIT_URL = "%s/articles/%d/block/edit";
private static final String REMOVE_URL = "%s/articles/%d/block/remove";
private static final String REPLACE_URL = "%s/articles/%d/replaceContent";
private static final String COPY_URL = "%s/articles/%d/block/copy";
@LocalServerPort
private int port;
@Autowired
private MockMvc mockMvc;
private StompSession session;
private ArticleDTO articleDTO;
private ArticleBlockDTO textBlock;
private ArticleBlockDTO pageBlock;
@Autowired
private ArticleBlockRepository articleBlockRepository;
@Autowired
private ArticleRepository articleRepository;
private WebSocketStompClient client;
SpaceDTO createSpace() throws Exception {
SpaceDTO request = new SpaceDTO().setTitle("TEST_SPACE").setProjectCode("TEST_SPACE")
.setJagaProjectId(generateUniqueJagaProjectId());
return TestUtil.convertJsonToObject(
mockMvc.perform(post(SPACE_CREATE_URL)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(request))
).andExpect(status().isCreated())
.andReturn().getResponse().getContentAsString(),
SpaceDTO.class);
}
ArticleDTO createArticle(Long spaceId) throws Exception {
RequestArticleDTO request = new RequestArticleDTO(null, "TEST_ARTICLE");
return TestUtil.convertJsonToObject(mockMvc.perform(post(ARTICLE_CREATE_URL, spaceId)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(request))
).andExpect(status().isCreated())
.andReturn().getResponse().getContentAsString(), ArticleDTO.class);
}
@BeforeEach
@Transactional
void init() throws Exception {
WebSocketStompClient stompClient = new WebSocketStompClient(new SockJsClient(
Collections.singletonList(new WebSocketTransport(new StandardWebSocketClient()))));
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
this.session = stompClient.connect(
WEBSOCKET_URL.formatted(port),
new StompSessionHandlerAdapter() {
}).get(1, SECONDS);
SpaceDTO spaceDTO = createSpace();
this.articleDTO = createArticle(spaceDTO.getId());
ArticleBlockDTO textBlock = articleDTO.getPayload().getItems().values()
.stream().filter(it -> it.payload().getType().equals(BlockType.TEXT)).findFirst()
.orElse(null);
assertThat(textBlock).isNotNull();
ArticleBlockDTO pageBlock = articleDTO.getPayload().getItems().values()
.stream().filter(it -> it.payload().getType().equals(BlockType.PAGE)).findFirst()
.orElse(null);
assertThat(pageBlock).isNotNull();
this.textBlock = textBlock;
this.pageBlock = pageBlock;
} .......
/**
* OAuth test utility.
*/
public class OAuth2TestUtil {
public static final String TEST_USER_LOGIN = "test";
public static final String ID_TOKEN =
"""
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9\
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsIm\
p0aSI6ImQzNWRmMTRkLTA5ZjYtNDhmZi04YTkzLTdjNmYwMzM5MzE1OSIsImlhdCI6MTU0M\
Tk3MTU4MywiZXhwIjoxNTQxOTc1MTgzfQ.QaQOarmV8xEUYV7yvWzX3cUE_4W1luMcWCwpr\
oqqUrg\
""";
/**
* OAuth2AuthenticationToken for tests.
*
* @return test OAuth2AuthenticationToken.
*/
public static OAuth2AuthenticationToken testAuthenticationToken() {
Map<String, Object> claims = new HashMap<>();
claims.put("sub", TEST_USER_LOGIN);
claims.put("preferred_username", TEST_USER_LOGIN);
claims.put("email", "[email protected]");
claims.put("roles", Collections.singletonList(AuthoritiesConstants.ADMIN));
return authenticationToken(claims);
}
/**
* OAuth2AuthenticationToken for tests.
*
* @param claims prepared claims.
* @return test token.
*/
public static OAuth2AuthenticationToken authenticationToken(Map<String, Object> claims) {
Instant issuedAt = Instant.now();
Instant expiresAt = Instant.now().plus(1, ChronoUnit.DAYS);
if (!claims.containsKey("sub")) {
claims.put("sub", "jane");
}
if (!claims.containsKey("preferred_username")) {
claims.put("preferred_username", "jane");
}
if (!claims.containsKey("email")) {
claims.put("email", "[email protected]");
}
if (claims.containsKey("auth_time")) {
issuedAt = (Instant) claims.get("auth_time");
} else {
claims.put("auth_time", issuedAt);
}
if (claims.containsKey("exp")) {
expiresAt = (Instant) claims.get("exp");
} else {
claims.put("exp", expiresAt);
}
Collection<GrantedAuthority> authorities = SecurityUtils.extractAuthorityFromClaims(claims);
OidcIdToken token = new OidcIdToken(ID_TOKEN, issuedAt, expiresAt, claims);
OidcUserInfo userInfo = new OidcUserInfo(claims);
DefaultOidcUser user = new DefaultOidcUser(authorities, token, userInfo, "preferred_username");
return new OAuth2AuthenticationToken(user, user.getAuthorities(), "oidc");
}
/**
* OAuth2AuthenticationToken for tests.
*
* @param authorizedClientService authorizedClientService.
* @param clientRegistration clientRegistration.
* @param authentication authentication.
* @return test token.
*/
public static OAuth2AuthenticationToken registerAuthenticationToken(
OAuth2AuthorizedClientService authorizedClientService,
ClientRegistration clientRegistration,
OAuth2AuthenticationToken authentication
) {
Map<String, Object> userDetails = authentication.getPrincipal().getAttributes();
OAuth2AccessToken token = new OAuth2AccessToken(
TokenType.BEARER,
"Token",
(Instant) userDetails.get("auth_time"),
(Instant) userDetails.get("exp")
);
authorizedClientService.saveAuthorizedClient(
new OAuth2AuthorizedClient(clientRegistration, authentication.getName(), token),
authentication
);
return authentication;
}
}
/**
* This class allows you to run unit and integration tests without an IdP.
*/
@TestConfiguration
@Import(OAuth2Configuration.class)
public class TestSecurityConfiguration {
@Bean
ClientRegistration clientRegistration() {
return clientRegistrationBuilder().build();
}
@Bean
ClientRegistrationRepository clientRegistrationRepository(ClientRegistration clientRegistration) {
return new InMemoryClientRegistrationRepository(clientRegistration);
}
private ClientRegistration.Builder clientRegistrationBuilder() {
Map<String, Object> metadata = new HashMap<>();
metadata.put("end_session_endpoint", "https://koschey.rt.ru/logout");
return ClientRegistration
.withRegistrationId("oidc")
.issuerUri("{baseUrl}")
.redirectUri("{baseUrl}/{action}/oauth2/code/{registrationId}")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.scope("read:user")
.authorizationUri("https://koschey.rt.ru/login/oauth/authorize")
.tokenUri("https://koschey.rt.ru/login/oauth/access_token")
.jwkSetUri("https://koschey.rt.ru/oauth/jwk")
.userInfoUri("https://api.koschey.rt.ru/user")
.providerConfigurationMetadata(metadata)
.userNameAttributeName("id")
.clientName("Client Name")
.clientId("client-id")
.clientSecret("client-secret");
}
@Bean
JwtDecoder jwtDecoder() {
return mock(JwtDecoder.class);
}
@Bean
OAuth2AuthorizedClientService authorizedClientService(
ClientRegistrationRepository clientRegistrationRepository) {
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
}
@Bean
@Primary
KeycloakService keycloakService() {
return new KeycloakService() {
private final Map<String, User> userMap =
Map.of("admin", new User()
.setId(UUID.randomUUID().toString())
.setEmail("admin@localhost")
.setLogin("admin@localhost")
.setFirstName("Admin")
.setLastName("Admin"),
"user", new User()
.setId(UUID.randomUUID().toString())
.setEmail("user@localhost")
.setLogin("user@localhost")
.setFirstName("User")
.setLastName("User"));
@Override
public Optional<User> getUserByLogin(final String login) {
return Optional.ofNullable(userMap.get(login));
}
@Override
public String getBearerToken() {
return "";
}
};
}
}
Upvotes: 0
Views: 18