mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-03-01 10:59:16 +00:00
Polish tests
Issue gh-11783 Issue gh-13763
This commit is contained in:
parent
80a8d3831a
commit
77c30c431e
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -38,8 +38,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.oauth2.client.AuthorizationCodeOAuth2AuthorizedClientProvider;
|
||||
@ -61,14 +59,9 @@ import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentia
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2PasswordGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2RefreshTokenGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.TokenExchangeGrantRequest;
|
||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
@ -80,13 +73,10 @@ import org.springframework.security.oauth2.core.TestOAuth2RefreshTokens;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.security.oauth2.jwt.JoseHeaderNames;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.jwt.JwtClaimNames;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -397,42 +387,32 @@ public class OAuth2AuthorizedClientManagerConfigurationTests {
|
||||
|
||||
@Bean
|
||||
OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeTokenResponseClient() {
|
||||
return new MockAuthorizationCodeClient();
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenTokenResponseClient() {
|
||||
return new MockRefreshTokenClient();
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsTokenResponseClient() {
|
||||
return new MockClientCredentialsClient();
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordTokenResponseClient() {
|
||||
return new MockPasswordClient();
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerTokenResponseClient() {
|
||||
return new MockJwtBearerClient();
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeTokenResponseClient() {
|
||||
return new MockTokenExchangeClient();
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
|
||||
return mock(DefaultOAuth2UserService.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
|
||||
return mock(OidcUserService.class);
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
}
|
||||
@ -449,35 +429,35 @@ public class OAuth2AuthorizedClientManagerConfigurationTests {
|
||||
@Bean
|
||||
RefreshTokenOAuth2AuthorizedClientProvider refreshTokenProvider() {
|
||||
RefreshTokenOAuth2AuthorizedClientProvider authorizedClientProvider = new RefreshTokenOAuth2AuthorizedClientProvider();
|
||||
authorizedClientProvider.setAccessTokenResponseClient(new MockRefreshTokenClient());
|
||||
authorizedClientProvider.setAccessTokenResponseClient(new MockAccessTokenResponseClient<>());
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ClientCredentialsOAuth2AuthorizedClientProvider clientCredentialsProvider() {
|
||||
ClientCredentialsOAuth2AuthorizedClientProvider authorizedClientProvider = new ClientCredentialsOAuth2AuthorizedClientProvider();
|
||||
authorizedClientProvider.setAccessTokenResponseClient(new MockClientCredentialsClient());
|
||||
authorizedClientProvider.setAccessTokenResponseClient(new MockAccessTokenResponseClient<>());
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
@Bean
|
||||
PasswordOAuth2AuthorizedClientProvider passwordProvider() {
|
||||
PasswordOAuth2AuthorizedClientProvider authorizedClientProvider = new PasswordOAuth2AuthorizedClientProvider();
|
||||
authorizedClientProvider.setAccessTokenResponseClient(new MockPasswordClient());
|
||||
authorizedClientProvider.setAccessTokenResponseClient(new MockAccessTokenResponseClient<>());
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
@Bean
|
||||
JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider() {
|
||||
JwtBearerOAuth2AuthorizedClientProvider authorizedClientProvider = new JwtBearerOAuth2AuthorizedClientProvider();
|
||||
authorizedClientProvider.setAccessTokenResponseClient(new MockJwtBearerClient());
|
||||
authorizedClientProvider.setAccessTokenResponseClient(new MockAccessTokenResponseClient<>());
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
@Bean
|
||||
TokenExchangeOAuth2AuthorizedClientProvider tokenExchangeAuthorizedClientProvider() {
|
||||
TokenExchangeOAuth2AuthorizedClientProvider authorizedClientProvider = new TokenExchangeOAuth2AuthorizedClientProvider();
|
||||
authorizedClientProvider.setAccessTokenResponseClient(new MockTokenExchangeClient());
|
||||
authorizedClientProvider.setAccessTokenResponseClient(new MockAccessTokenResponseClient<>());
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
@ -485,21 +465,10 @@ public class OAuth2AuthorizedClientManagerConfigurationTests {
|
||||
|
||||
abstract static class OAuth2ClientBaseConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
|
||||
.oauth2Login(Customizer.withDefaults())
|
||||
.oauth2Client(Customizer.withDefaults());
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
ClientRegistrationRepository clientRegistrationRepository() {
|
||||
// @formatter:off
|
||||
return new InMemoryClientRegistrationRepository(Arrays.asList(
|
||||
return new InMemoryClientRegistrationRepository(
|
||||
CommonOAuth2Provider.GOOGLE.getBuilder("google")
|
||||
.clientId("google-client-id")
|
||||
.clientSecret("google-client-secret")
|
||||
@ -527,7 +496,7 @@ public class OAuth2AuthorizedClientManagerConfigurationTests {
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.TOKEN_EXCHANGE)
|
||||
.scope("user.read", "user.write")
|
||||
.build()));
|
||||
.build());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@ -558,60 +527,11 @@ public class OAuth2AuthorizedClientManagerConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
private static class MockAuthorizationCodeClient
|
||||
implements OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
|
||||
private static class MockAccessTokenResponseClient<T extends AbstractOAuth2AuthorizationGrantRequest>
|
||||
implements OAuth2AccessTokenResponseClient<T> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(
|
||||
OAuth2AuthorizationCodeGrantRequest authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockRefreshTokenClient
|
||||
implements OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(OAuth2RefreshTokenGrantRequest authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockClientCredentialsClient
|
||||
implements OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(
|
||||
OAuth2ClientCredentialsGrantRequest authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockPasswordClient implements OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(OAuth2PasswordGrantRequest authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockJwtBearerClient implements OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(JwtBearerGrantRequest authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockTokenExchangeClient implements OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(TokenExchangeGrantRequest authorizationGrantRequest) {
|
||||
public OAuth2AccessTokenResponse getTokenResponse(T authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -53,7 +53,6 @@ import org.springframework.security.oauth2.client.TokenExchangeOAuth2AuthorizedC
|
||||
import org.springframework.security.oauth2.client.endpoint.AbstractOAuth2AuthorizationGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.JwtBearerGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2PasswordGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2RefreshTokenGrantRequest;
|
||||
@ -430,114 +429,65 @@ public class OAuth2AuthorizedClientManagerRegistrarTests {
|
||||
});
|
||||
}
|
||||
|
||||
public static AuthorizationCodeOAuth2AuthorizedClientProvider authorizationCodeAuthorizedClientProvider() {
|
||||
public static AuthorizationCodeOAuth2AuthorizedClientProvider authorizationCode() {
|
||||
return spy(new AuthorizationCodeOAuth2AuthorizedClientProvider());
|
||||
}
|
||||
|
||||
public static RefreshTokenOAuth2AuthorizedClientProvider refreshTokenAuthorizedClientProvider() {
|
||||
public static RefreshTokenOAuth2AuthorizedClientProvider refreshToken() {
|
||||
RefreshTokenOAuth2AuthorizedClientProvider authorizedClientProvider = new RefreshTokenOAuth2AuthorizedClientProvider();
|
||||
authorizedClientProvider.setAccessTokenResponseClient(refreshTokenAccessTokenResponseClient());
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
public static MockRefreshTokenClient refreshTokenAccessTokenResponseClient() {
|
||||
return new MockRefreshTokenClient();
|
||||
public static OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() {
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
public static ClientCredentialsOAuth2AuthorizedClientProvider clientCredentialsAuthorizedClientProvider() {
|
||||
public static ClientCredentialsOAuth2AuthorizedClientProvider clientCredentials() {
|
||||
ClientCredentialsOAuth2AuthorizedClientProvider authorizedClientProvider = new ClientCredentialsOAuth2AuthorizedClientProvider();
|
||||
authorizedClientProvider.setAccessTokenResponseClient(clientCredentialsAccessTokenResponseClient());
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
public static OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
|
||||
return new MockClientCredentialsClient();
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
public static PasswordOAuth2AuthorizedClientProvider passwordAuthorizedClientProvider() {
|
||||
public static PasswordOAuth2AuthorizedClientProvider password() {
|
||||
PasswordOAuth2AuthorizedClientProvider authorizedClientProvider = new PasswordOAuth2AuthorizedClientProvider();
|
||||
authorizedClientProvider.setAccessTokenResponseClient(passwordAccessTokenResponseClient());
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
public static OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordAccessTokenResponseClient() {
|
||||
return new MockPasswordClient();
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
public static JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider() {
|
||||
public static JwtBearerOAuth2AuthorizedClientProvider jwtBearer() {
|
||||
JwtBearerOAuth2AuthorizedClientProvider authorizedClientProvider = new JwtBearerOAuth2AuthorizedClientProvider();
|
||||
authorizedClientProvider.setAccessTokenResponseClient(jwtBearerAccessTokenResponseClient());
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
public static OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() {
|
||||
return new MockJwtBearerClient();
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
public static TokenExchangeOAuth2AuthorizedClientProvider tokenExchangeAuthorizedClientProvider() {
|
||||
public static TokenExchangeOAuth2AuthorizedClientProvider tokenExchange() {
|
||||
TokenExchangeOAuth2AuthorizedClientProvider authorizedClientProvider = new TokenExchangeOAuth2AuthorizedClientProvider();
|
||||
authorizedClientProvider.setAccessTokenResponseClient(tokenExchangeAccessTokenResponseClient());
|
||||
return authorizedClientProvider;
|
||||
}
|
||||
|
||||
public static OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeAccessTokenResponseClient() {
|
||||
return new MockTokenExchangeClient();
|
||||
return new MockAccessTokenResponseClient<>();
|
||||
}
|
||||
|
||||
private static class MockAuthorizationCodeClient
|
||||
implements OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
|
||||
private static class MockAccessTokenResponseClient<T extends AbstractOAuth2AuthorizationGrantRequest>
|
||||
implements OAuth2AccessTokenResponseClient<T> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(
|
||||
OAuth2AuthorizationCodeGrantRequest authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockRefreshTokenClient
|
||||
implements OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(OAuth2RefreshTokenGrantRequest authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockClientCredentialsClient
|
||||
implements OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(
|
||||
OAuth2ClientCredentialsGrantRequest authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockPasswordClient implements OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(OAuth2PasswordGrantRequest authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockJwtBearerClient implements OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(JwtBearerGrantRequest authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockTokenExchangeClient implements OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(TokenExchangeGrantRequest authorizationGrantRequest) {
|
||||
public OAuth2AccessTokenResponse getTokenResponse(T authorizationGrantRequest) {
|
||||
return MOCK_RESPONSE_CLIENT.getTokenResponse(authorizationGrantRequest);
|
||||
}
|
||||
|
||||
|
@ -42,21 +42,21 @@
|
||||
factory-method="authorizedClientManagerConsumer"/>
|
||||
|
||||
<b:bean class="org.springframework.security.config.http.OAuth2AuthorizedClientManagerRegistrarTests"
|
||||
factory-method="authorizationCodeAuthorizedClientProvider"/>
|
||||
factory-method="authorizationCode"/>
|
||||
|
||||
<b:bean class="org.springframework.security.config.http.OAuth2AuthorizedClientManagerRegistrarTests"
|
||||
factory-method="refreshTokenAuthorizedClientProvider"/>
|
||||
factory-method="refreshToken"/>
|
||||
|
||||
<b:bean class="org.springframework.security.config.http.OAuth2AuthorizedClientManagerRegistrarTests"
|
||||
factory-method="clientCredentialsAuthorizedClientProvider"/>
|
||||
factory-method="clientCredentials"/>
|
||||
|
||||
<b:bean class="org.springframework.security.config.http.OAuth2AuthorizedClientManagerRegistrarTests"
|
||||
factory-method="passwordAuthorizedClientProvider"/>
|
||||
factory-method="password"/>
|
||||
|
||||
<b:bean class="org.springframework.security.config.http.OAuth2AuthorizedClientManagerRegistrarTests"
|
||||
factory-method="jwtBearerAuthorizedClientProvider"/>
|
||||
factory-method="jwtBearer"/>
|
||||
|
||||
<b:bean class="org.springframework.security.config.http.OAuth2AuthorizedClientManagerRegistrarTests"
|
||||
factory-method="tokenExchangeAuthorizedClientProvider"/>
|
||||
factory-method="tokenExchange"/>
|
||||
|
||||
</b:beans>
|
Loading…
x
Reference in New Issue
Block a user