Skip to content

Commit 491e40a

Browse files
Sheikah45Brutus5000
authored andcommitted
Add hmac to user and api
1 parent 355071e commit 491e40a

File tree

6 files changed

+76
-37
lines changed

6 files changed

+76
-37
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.faforever.client.api;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import lombok.extern.slf4j.Slf4j;
5+
import org.jetbrains.annotations.NotNull;
6+
import org.springframework.http.HttpHeaders;
7+
import org.springframework.stereotype.Component;
8+
import org.springframework.web.reactive.function.client.ClientRequest;
9+
import org.springframework.web.reactive.function.client.ClientResponse;
10+
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
11+
import org.springframework.web.reactive.function.client.ExchangeFunction;
12+
import reactor.core.publisher.Mono;
13+
14+
@Component
15+
@RequiredArgsConstructor
16+
@Slf4j
17+
public class HmacTokenFilter implements ExchangeFilterFunction {
18+
private final TokenRetriever tokenRetriever;
19+
20+
@Override
21+
public @NotNull Mono<ClientResponse> filter(@NotNull ClientRequest request, @NotNull ExchangeFunction next) {
22+
return tokenRetriever.getRefreshedHmacValue().flatMap(hmac -> next.exchange(ClientRequest.from(request)
23+
.headers(headers -> headers.add("X-HMAC", hmac))
24+
.build()));
25+
}
26+
}

src/main/java/com/faforever/client/api/TokenRetriever.java

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.faforever.client.login.NoRefreshTokenException;
66
import com.faforever.client.login.TokenRetrievalException;
77
import com.faforever.client.preferences.LoginPrefs;
8+
import com.nimbusds.jwt.JWTParser;
89
import javafx.beans.property.SimpleStringProperty;
910
import javafx.beans.property.StringProperty;
1011
import lombok.RequiredArgsConstructor;
@@ -41,9 +42,8 @@ public class TokenRetriever implements InitializingBean {
4142
private final Flux<Long> invalidateFlux = invalidateSink.asFlux().publish().autoConnect();
4243
private final StringProperty refreshTokenValue = new SimpleStringProperty();
4344

44-
private final Mono<String> refreshedTokenMono = Mono.defer(this::refreshAccess)
45-
.cacheInvalidateWhen(this::getExpirationMono)
46-
.map(OAuth2AccessToken::getTokenValue);
45+
private final Mono<OAuth2AccessToken> refreshedTokenMono = Mono.defer(this::refreshAccess)
46+
.cacheInvalidateWhen(this::getExpirationMono);
4747

4848
@Override
4949
public void afterPropertiesSet() throws Exception {
@@ -59,7 +59,17 @@ private Mono<Void> getExpirationMono(OAuth2AccessToken token) {
5959
}
6060

6161
public Mono<String> getRefreshedTokenValue() {
62-
return refreshedTokenMono.doOnError(this::onTokenError);
62+
return refreshedTokenMono.map(OAuth2AccessToken::getTokenValue).doOnError(this::onTokenError);
63+
}
64+
65+
public Mono<String> getRefreshedHmacValue() {
66+
return getRefreshedTokenValue().flatMap(tokenValue -> {
67+
try {
68+
return Mono.just(JWTParser.parse(tokenValue).getJWTClaimsSet().getJSONObjectClaim("ext").get("hmac").toString());
69+
} catch (Exception e) {
70+
return Mono.error(e);
71+
}
72+
});
6373
}
6474

6575
public Mono<Void> loginWithAuthorizationCode(String code, String codeVerifier, URI redirectUri) {
@@ -99,26 +109,26 @@ private Mono<OAuth2AccessToken> refreshAccess() {
99109

100110
private Mono<OAuth2AccessToken> retrieveToken(MultiValueMap<String, String> properties) {
101111
return defaultWebClient.post()
102-
.uri(String.format("%s/oauth2/token", clientProperties.getOauth().getBaseUrl()))
103-
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
104-
.accept(MediaType.APPLICATION_JSON)
105-
.bodyValue(properties)
106-
.exchangeToMono(response -> {
107-
if (response.statusCode().isError()) {
108-
return response.bodyToMono(String.class)
109-
.switchIfEmpty(Mono.just(response.statusCode().toString()))
110-
.flatMap(body -> Mono.error(new TokenRetrievalException(body)));
111-
}
112-
113-
return response.body(OAuth2BodyExtractors.oauth2AccessTokenResponse());
114-
})
115-
.doOnSubscribe(subscription -> log.debug("Retrieving OAuth token"))
116-
.doOnNext(tokenResponse -> {
117-
OAuth2RefreshToken refreshToken = tokenResponse.getRefreshToken();
118-
refreshTokenValue.set(refreshToken != null ? refreshToken.getTokenValue() : null);
119-
})
120-
.map(OAuth2AccessTokenResponse::getAccessToken)
121-
.doOnNext(token -> log.info("Token valid until {}", token.getExpiresAt()));
112+
.uri(String.format("%s/oauth2/token", clientProperties.getOauth().getBaseUrl()))
113+
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
114+
.accept(MediaType.APPLICATION_JSON)
115+
.bodyValue(properties)
116+
.exchangeToMono(response -> {
117+
if (response.statusCode().isError()) {
118+
return response.bodyToMono(String.class)
119+
.switchIfEmpty(Mono.just(response.statusCode().toString()))
120+
.flatMap(body -> Mono.error(new TokenRetrievalException(body)));
121+
}
122+
123+
return response.body(OAuth2BodyExtractors.oauth2AccessTokenResponse());
124+
})
125+
.doOnSubscribe(subscription -> log.debug("Retrieving OAuth token"))
126+
.doOnNext(tokenResponse -> {
127+
OAuth2RefreshToken refreshToken = tokenResponse.getRefreshToken();
128+
refreshTokenValue.set(refreshToken != null ? refreshToken.getTokenValue() : null);
129+
})
130+
.map(OAuth2AccessTokenResponse::getAccessToken)
131+
.doOnNext(token -> log.info("Token valid until {}", token.getExpiresAt()));
122132
}
123133

124134
public void invalidateToken() {
@@ -129,8 +139,4 @@ public void invalidateToken() {
129139
public Flux<Long> invalidationFlux() {
130140
return invalidateFlux;
131141
}
132-
133-
public Mono<String> getAccessToken() {
134-
return refreshedTokenMono;
135-
}
136142
}

src/main/java/com/faforever/client/config/WebClientConfig.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.faforever.client.config;
22

3+
import com.faforever.client.api.HmacTokenFilter;
34
import com.faforever.client.api.OAuthTokenFilter;
45
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
56
import org.springframework.context.annotation.Bean;
@@ -18,15 +19,21 @@ public WebClient defaultWebClient(WebClient.Builder webClientBuilder) {
1819
@Bean
1920
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
2021
public WebClient apiWebClient(WebClient.Builder webClientBuilder, OAuthTokenFilter oAuthTokenFilter,
21-
ClientProperties clientProperties) {
22-
return webClientBuilder.baseUrl(clientProperties.getApi().getBaseUrl()).filter(oAuthTokenFilter).build();
22+
HmacTokenFilter hmacTokenFilter, ClientProperties clientProperties) {
23+
return webClientBuilder.baseUrl(clientProperties.getApi().getBaseUrl())
24+
.filter(oAuthTokenFilter)
25+
.filter(hmacTokenFilter)
26+
.build();
2327
}
2428

2529
@Bean
2630
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
2731
public WebClient userWebClient(WebClient.Builder webClientBuilder, OAuthTokenFilter oAuthTokenFilter,
28-
ClientProperties clientProperties) {
29-
return webClientBuilder.baseUrl(clientProperties.getUser().getBaseUrl()).filter(oAuthTokenFilter).build();
32+
HmacTokenFilter hmacTokenFilter, ClientProperties clientProperties) {
33+
return webClientBuilder.baseUrl(clientProperties.getUser().getBaseUrl())
34+
.filter(oAuthTokenFilter)
35+
.filter(hmacTokenFilter)
36+
.build();
3037
}
3138

3239
}

src/main/java/com/faforever/client/headerbar/UserButtonController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public void onReport() {
6565
}
6666

6767
public void onCopyAccessToken() {
68-
tokenRetriever.getAccessToken().publishOn(fxApplicationThreadExecutor.asScheduler()).subscribe(accessToken -> {
68+
tokenRetriever.getRefreshedTokenValue().publishOn(fxApplicationThreadExecutor.asScheduler()).subscribe(accessToken -> {
6969
log.info("Copied access token to clipboard");
7070
ClipboardUtil.copyToClipboard(accessToken);
7171
});

src/test/java/com/faforever/client/api/TokenRetrieverTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,8 @@ public void testGetAccessToken() throws Exception {
191191
TOKEN_TYPE, "bearer");
192192
prepareTokenResponse(tokenProperties);
193193

194-
StepVerifier.create(instance.getAccessToken())
195-
.assertNext(accessToken -> assertEquals(accessToken, "test"))
194+
StepVerifier.create(instance.getRefreshedTokenValue())
195+
.assertNext(accessToken -> assertEquals("test", accessToken))
196196
.verifyComplete();
197197
}
198198
}

src/test/java/com/faforever/client/headerbar/UserButtonControllerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ public void testReport() {
7171

7272
@Test
7373
public void testCopyAccessToken() {
74-
when(tokenRetriever.getAccessToken()).thenReturn(Mono.just("someToken"));
74+
when(tokenRetriever.getRefreshedTokenValue()).thenReturn(Mono.just("someToken"));
7575

7676
instance.onCopyAccessToken();
7777

78-
verify(tokenRetriever).getAccessToken();
78+
verify(tokenRetriever).getRefreshedTokenValue();
7979
}
8080

8181
@Test

0 commit comments

Comments
 (0)