Skip to content

Commit 16469f3

Browse files
authored
Merge pull request #18 from graphql-java-kickstart/update-oauth-security
Replace deprecated code fix #17
2 parents 662df7e + f59b258 commit 16469f3

File tree

7 files changed

+149
-16
lines changed

7 files changed

+149
-16
lines changed

graphql-webclient-spring-boot-autoconfigure/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ dependencies {
66
implementation "org.springframework.boot:spring-boot-autoconfigure"
77
implementation "org.springframework.boot:spring-boot-starter-webflux"
88
implementation "org.springframework.security:spring-security-oauth2-client"
9+
10+
testImplementation "org.springframework.boot:spring-boot-starter-test"
911
}

graphql-webclient-spring-boot-autoconfigure/src/main/java/graphql/kickstart/spring/webclient/boot/GraphQLWebClientAutoConfiguration.java

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package graphql.kickstart.spring.webclient.boot;
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import lombok.NonNull;
45
import lombok.RequiredArgsConstructor;
56
import lombok.extern.slf4j.Slf4j;
67
import org.springframework.beans.factory.annotation.Autowired;
@@ -13,15 +14,17 @@
1314
import org.springframework.context.annotation.Bean;
1415
import org.springframework.context.annotation.ComponentScan;
1516
import org.springframework.context.annotation.Configuration;
17+
import org.springframework.security.oauth2.client.AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager;
18+
import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService;
1619
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
1720
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
18-
import org.springframework.security.oauth2.client.web.server.UnAuthenticatedServerOAuth2AuthorizedClientRepository;
1921
import org.springframework.web.reactive.function.client.WebClient;
2022

2123
@Slf4j
2224
@Configuration
2325
@RequiredArgsConstructor
24-
@AutoConfigureAfter({JacksonAutoConfiguration.class, OAuth2ClientAutoConfiguration.class, WebFluxAutoConfiguration.class})
26+
@AutoConfigureAfter({JacksonAutoConfiguration.class, OAuth2ClientAutoConfiguration.class,
27+
WebFluxAutoConfiguration.class})
2528
@EnableConfigurationProperties(GraphQLClientProperties.class)
2629
@ComponentScan(basePackageClasses = GraphQLWebClientImpl.class)
2730
public class GraphQLWebClientAutoConfiguration {
@@ -36,18 +39,33 @@ public WebClient webClient(
3639
) {
3740
clientBuilder.baseUrl(graphqlClientProperties.getUrl());
3841

39-
if (clientRegistrations != null && clientRegistrations.findByRegistrationId("graphql").blockOptional().isPresent()) {
40-
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
41-
new ServerOAuth2AuthorizedClientExchangeFilterFunction(
42-
clientRegistrations,
43-
new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
44-
oauth.setDefaultClientRegistrationId("graphql");
45-
clientBuilder.filter(oauth);
42+
if (isGraphQLClientRegistrationPresent(clientRegistrations)) {
43+
clientBuilder.filter(createOAuthFilter(clientRegistrations));
4644
}
4745

4846
return clientBuilder.build();
4947
}
5048

49+
@NonNull
50+
private ServerOAuth2AuthorizedClientExchangeFilterFunction createOAuthFilter(
51+
ReactiveClientRegistrationRepository clientRegistrations) {
52+
InMemoryReactiveOAuth2AuthorizedClientService clientService =
53+
new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrations);
54+
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
55+
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations,
56+
clientService);
57+
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
58+
new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
59+
oauth.setDefaultClientRegistrationId("graphql");
60+
return oauth;
61+
}
62+
63+
private boolean isGraphQLClientRegistrationPresent(
64+
ReactiveClientRegistrationRepository clientRegistrations) {
65+
return clientRegistrations != null && clientRegistrations.findByRegistrationId("graphql")
66+
.blockOptional().isPresent();
67+
}
68+
5169
@Bean
5270
@ConditionalOnMissingBean
5371
public ObjectMapper objectMapper() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package graphql.kickstart.spring.webclient.boot;
2+
3+
import static org.junit.jupiter.api.Assertions.assertNotNull;
4+
import static org.mockito.ArgumentMatchers.isA;
5+
import static org.mockito.Mockito.mock;
6+
import static org.mockito.Mockito.times;
7+
import static org.mockito.Mockito.verify;
8+
import static org.mockito.Mockito.when;
9+
10+
import com.fasterxml.jackson.databind.ObjectMapper;
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.Test;
13+
import org.springframework.security.oauth2.client.registration.ClientRegistration;
14+
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
15+
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
16+
import org.springframework.security.oauth2.core.AuthorizationGrantType;
17+
import org.springframework.web.reactive.function.client.WebClient;
18+
import reactor.core.publisher.Mono;
19+
20+
class GraphQLWebClientAutoConfigurationTest {
21+
22+
private GraphQLWebClientAutoConfiguration configuration;
23+
private WebClient.Builder mockClientBuilder;
24+
25+
@BeforeEach
26+
void setup() {
27+
GraphQLClientProperties graphQLClientProperties = new GraphQLClientProperties();
28+
configuration = new GraphQLWebClientAutoConfiguration(graphQLClientProperties);
29+
30+
mockClientBuilder = mock(WebClient.Builder.class);
31+
}
32+
33+
@Test
34+
void webClient_nullClientRegistrations_doesNotAddFilter() {
35+
configuration.webClient(mockClientBuilder, null);
36+
verify(mockClientBuilder, times(0))
37+
.filter(isA(ServerOAuth2AuthorizedClientExchangeFilterFunction.class));
38+
}
39+
40+
@Test
41+
void webClient_noGraphQLRegistration_doesNotAddFilter() {
42+
var registrationRepository = mock(ReactiveClientRegistrationRepository.class);
43+
when(registrationRepository.findByRegistrationId("graphql")).thenReturn(Mono.empty());
44+
configuration.webClient(mockClientBuilder, registrationRepository);
45+
verify(mockClientBuilder, times(0))
46+
.filter(isA(ServerOAuth2AuthorizedClientExchangeFilterFunction.class));
47+
}
48+
49+
@Test
50+
void webClient_withGraphQLRegistration_doesAddFilter() {
51+
var registrationRepository = mock(ReactiveClientRegistrationRepository.class);
52+
var registration = ClientRegistration.withRegistrationId("graphql")
53+
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
54+
.clientId("clientId")
55+
.clientSecret("clientSecret")
56+
.tokenUri("tokenUri")
57+
.build();
58+
when(registrationRepository.findByRegistrationId("graphql")).thenReturn(Mono.just(registration));
59+
configuration.webClient(mockClientBuilder, registrationRepository);
60+
verify(mockClientBuilder, times(1))
61+
.filter(isA(ServerOAuth2AuthorizedClientExchangeFilterFunction.class));
62+
}
63+
64+
@Test
65+
void webClient_getObjectMapper_returns() {
66+
assertNotNull(configuration.objectMapper());
67+
}
68+
69+
@Test
70+
void webClient_graphQLWebClient_returns() {
71+
assertNotNull(configuration.graphQLWebClient(WebClient.builder().build(), new ObjectMapper()));
72+
}
73+
74+
}

graphql-webclient/src/main/java/graphql/kickstart/spring/webclient/boot/GraphQLError.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ public class GraphQLError {
1010
private String message;
1111
private List<Location> locations;
1212
private List<String> path;
13-
private Map<String, Object> extensions ;
13+
private Map<String, Object> extensions;
1414

1515
}

graphql-webclient/src/main/java/graphql/kickstart/spring/webclient/boot/GraphQLErrorsException.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22

33
import java.util.List;
44
import lombok.EqualsAndHashCode;
5-
import lombok.RequiredArgsConstructor;
5+
import lombok.NonNull;
66
import lombok.Value;
77

88
@Value
99
@EqualsAndHashCode(callSuper = false)
10-
@RequiredArgsConstructor
1110
public class GraphQLErrorsException extends RuntimeException {
1211

13-
List<GraphQLError> errors;
12+
transient List<GraphQLError> errors;
13+
String message;
1414

15-
@Override
16-
public String getMessage() {
17-
return errors.get(0).getMessage();
15+
public GraphQLErrorsException(@NonNull List<GraphQLError> errors) {
16+
if (errors.isEmpty()) {
17+
throw new IllegalArgumentException("errors must not be empty");
18+
}
19+
this.errors = errors;
20+
this.message = errors.get(0).getMessage();
1821
}
1922

2023
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package graphql.kickstart.spring.webclient.boot;
2+
3+
import static java.util.Collections.emptyList;
4+
import static org.junit.jupiter.api.Assertions.*;
5+
6+
import java.util.List;
7+
import org.junit.jupiter.api.Test;
8+
9+
@SuppressWarnings("ThrowableNotThrown")
10+
class GraphQLErrorsExceptionTest {
11+
12+
@Test
13+
void construct_nullArg_throwsException() {
14+
//noinspection ConstantConditions
15+
assertThrows(NullPointerException.class, () -> new GraphQLErrorsException(null));
16+
}
17+
18+
@Test
19+
void construct_emptyArg_throwsException() {
20+
List<GraphQLError> emptyList = emptyList();
21+
assertThrows(IllegalArgumentException.class, () -> new GraphQLErrorsException(emptyList));
22+
}
23+
24+
@Test
25+
void construct_errors_returnsErrorsAndFirstMessage() {
26+
var error = new GraphQLError();
27+
error.setMessage("testmessage");
28+
var errors = List.of(error);
29+
GraphQLErrorsException e = new GraphQLErrorsException(errors);
30+
assertEquals(errors, e.getErrors());
31+
assertEquals("testmessage", e.getMessage());
32+
assertEquals("testmessage", e.getLocalizedMessage());
33+
}
34+
35+
}

lombok.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lombok.addLombokGeneratedAnnotation = true

0 commit comments

Comments
 (0)