mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Fix oauth model
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package com.imgfloat.app.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.http.converter.FormHttpMessageConverter;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
final class OAuth2RestTemplateFactory {
|
||||
|
||||
private OAuth2RestTemplateFactory() {
|
||||
}
|
||||
|
||||
static RestTemplate create() {
|
||||
RestTemplate restTemplate = new RestTemplate(Arrays.asList(
|
||||
new FormHttpMessageConverter(),
|
||||
new OAuth2AccessTokenResponseHttpMessageConverter()
|
||||
));
|
||||
ClientHttpRequestFactory requestFactory = restTemplate.getRequestFactory();
|
||||
if (requestFactory instanceof SimpleClientHttpRequestFactory simple) {
|
||||
simple.setConnectTimeout(30_000);
|
||||
simple.setReadTimeout(30_000);
|
||||
}
|
||||
return restTemplate;
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,14 @@ package com.imgfloat.app.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@@ -21,9 +24,20 @@ public class SecurityConfig {
|
||||
.requestMatchers("/ws/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.oauth2Login(Customizer.withDefaults())
|
||||
.oauth2Login(oauth -> oauth
|
||||
.tokenEndpoint(token -> token.accessTokenResponseClient(twitchAccessTokenResponseClient()))
|
||||
)
|
||||
.logout(logout -> logout.logoutSuccessUrl("/").permitAll())
|
||||
.csrf(csrf -> csrf.ignoringRequestMatchers("/ws/**", "/api/**"));
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> twitchAccessTokenResponseClient() {
|
||||
DefaultAuthorizationCodeTokenResponseClient delegate = new DefaultAuthorizationCodeTokenResponseClient();
|
||||
RestTemplate restTemplate = OAuth2RestTemplateFactory.create();
|
||||
restTemplate.setErrorHandler(new TwitchOAuth2ErrorResponseErrorHandler());
|
||||
delegate.setRestOperations(restTemplate);
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.imgfloat.app.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
/**
|
||||
* Twitch occasionally returns error payloads without an {@code error} code field. The default
|
||||
* {@link OAuth2ErrorHttpMessageConverter} refuses to deserialize such payloads and throws an
|
||||
* {@link HttpMessageNotReadableException}. That propagates up as a 500 before we can surface a
|
||||
* meaningful login failure to the user. This handler falls back to a safe, synthetic
|
||||
* {@link OAuth2Error} so the login flow can fail gracefully.
|
||||
*/
|
||||
class TwitchOAuth2ErrorResponseErrorHandler extends OAuth2ErrorResponseErrorHandler {
|
||||
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
try {
|
||||
super.handleError(response);
|
||||
} catch (HttpMessageNotReadableException ex) {
|
||||
throw asAuthorizationException(response, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private OAuth2AuthorizationException asAuthorizationException(ClientHttpResponse response,
|
||||
HttpMessageNotReadableException ex) throws IOException {
|
||||
String body = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);
|
||||
String description = "Failed to parse Twitch OAuth error response" + (body.isBlank() ? "." : ": " + body);
|
||||
OAuth2Error oauth2Error = new OAuth2Error("invalid_token_response", description, null);
|
||||
return new OAuth2AuthorizationException(oauth2Error, ex);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user