Как создать подключение к веб-сокету в Java-тестах Spring, ошибка 401JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Как создать подключение к веб-сокету в Java-тестах Spring, ошибка 401

Сообщение Anonymous »

Это блок теста интеграции кода, в котором возникает ошибка HttpClientErrorException$Unauthorized: 401. Проблема возникает в строке this.session = stompClient.connect(...) при создании сеанса. URL-адрес и порт имеют значение 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);

В нашем проекте аутентификация происходит через токен.
  • Но например почти все интеграционные тесты на конечных точках REST работают без аутентификации, есть один тест REST, в котором прописана аутентификация — в контексте безопасности объект аутентификации передается с установленным «тестовым» токеном (описан в OAuth2TestUtil).

    Я пытался установить объект аутентификации в тесте веб-сокета в контексте безопасности - но это не помогло. Ниже приведен пример кода, показывающий, как была установлена ​​аутентификация в интеграционном тесте REST:
    @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 описан в конце статьи
Ниже приведен полный тестовый код
/**
* 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 claims = new HashMap();
claims.put("sub", TEST_USER_LOGIN);
claims.put("preferred_username", TEST_USER_LOGIN);
claims.put("email", "john.doe@koschey.rt.ru");
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 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", "jane.doe@koschey.rt.ru");
}
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 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 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 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 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 getUserByLogin(final String login) {
return Optional.ofNullable(userMap.get(login));
}

@Override
public String getBearerToken() {
return "";
}
};
}
}


Подробнее здесь: https://stackoverflow.com/questions/791 ... -401-error
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»