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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
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.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@@ -21,9 +24,20 @@ public class SecurityConfig {
|
|||||||
.requestMatchers("/ws/**").permitAll()
|
.requestMatchers("/ws/**").permitAll()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.oauth2Login(Customizer.withDefaults())
|
.oauth2Login(oauth -> oauth
|
||||||
|
.tokenEndpoint(token -> token.accessTokenResponseClient(twitchAccessTokenResponseClient()))
|
||||||
|
)
|
||||||
.logout(logout -> logout.logoutSuccessUrl("/").permitAll())
|
.logout(logout -> logout.logoutSuccessUrl("/").permitAll())
|
||||||
.csrf(csrf -> csrf.ignoringRequestMatchers("/ws/**", "/api/**"));
|
.csrf(csrf -> csrf.ignoringRequestMatchers("/ws/**", "/api/**"));
|
||||||
return http.build();
|
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