HTTP-403 bei der Authentifizierung im Spring-Authentifizierungsserver nach /login im Spring Cloud GatewayJava

Java-Forum
Anonymous
 HTTP-403 bei der Authentifizierung im Spring-Authentifizierungsserver nach /login im Spring Cloud Gateway

Post by Anonymous »

Ich versuche, die Zusammenarbeit von Gateway und Autorisierungsserver einzurichten.
Hilf mir, Fehler im Programm zu finden, wenn ich mich authentifiziere und das Web-Authentifizierungsformular username= eingebe

Code: Select all

admin
und Passwort=

Code: Select all

1
Ich erhalte den http-Fehlercode 403 – verboten und der Browser zeigt eine Webseite mit den Worten „Zugriff verweigert“ an. Das Projekt besteht aus zwei Maven-Modulen: Spring Cloud Gateway und Spring Authorization Server
Autorisierungsserver gibt den Autorisierungscode zurück, wenn ich den Link http://localhost:9000/oauth2/authorize? ... host:8080/ in den Browser setze. Und gibt access_token zurück, wenn ich Code ausführe:

Code: Select all

curl -X POST 'http://localhost:9000/oauth2/token' \
--header "Authorization: Basic Z2F0ZXdheTpzZWNyZXQ=" \
--header "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=gateway" \
-d "redirect_uri=http://localhost:8080/" \
-d "grant_type=authorization_code" \
-d "code=EHZl1xZY7WNF0hNzcWbA8jgBYzlAoQWphmBUEaZLUE2VAw0hDIDB4A-E6emLZl_rK3tRm8HCEYRb8vvAKvc9NVACQnFJ6RO3Yeo19O9ibyFtU2gYmn3BJKgM0zep6CF9"
aber wenn ich versuche, mich über localhost:8080/login zu authentifizieren, erhalte ich 403 im Netzwerk. Der Autorisierungsserver hat ein leeres Protokoll und das Gateway zeigt Folgendes an:
Keine Routendefinition gefunden für [Exchange: GET http://localhost:8080/favicon.ico]
Ein weiterer Fehler – wenn ich dem Link mit localhost:8080 folge – http://localhost:8080/oauth2/authorize? ... host:8080/ Browser leitet zu localhost:9000/login weiter

Code: Select all

//Auth2CloudGatewayApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Auth2CloudGatewayApplication {

public static void main(String[] args) {
SpringApplication.run(Auth2CloudGatewayApplication.class, args);
}

}
//GatewaySecurityConfig.java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtValidators;
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebFluxSecurity
public class GatewaySecurityConfig {
@Value("${provider.issuer-uri}/oauth2/jwks")
private String jwkSetUri;
@Value("${provider.issuer-uri}")
private String issuerUri;
@Bean
SecurityWebFilterChain defaultSecurityFilterChain(ServerHttpSecurity http) throws Exception {
http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
.authorizeExchange(exchanges -> {
exchanges.pathMatchers("/login").permitAll();
exchanges.pathMatchers("/oauth2/**").permitAll();
exchanges.pathMatchers("/index.html").permitAll();
exchanges.pathMatchers("/favicon.ico").permitAll();
exchanges.pathMatchers("/assets/**").permitAll();
exchanges.pathMatchers("/**").permitAll();
exchanges.anyExchange().authenticated();
})
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(
withDefaults())
);
return http.build();
}

@Bean
public ReactiveJwtDecoder jwtDecoder() {
NimbusReactiveJwtDecoder jwtDecoder= NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build();
OAuth2TokenValidator withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
jwtDecoder.setJwtValidator(  new DelegatingOAuth2TokenValidator(withIssuer));//, withOperation)  );
return jwtDecoder;
}
}
//GatewayRoutesConfig.java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration

public class GatewayRoutesConfig {
@Value("${provider.issuer-uri}")
String authorization_server;
@Bean
public RouteLocator gatewayRoutes(RouteLocatorBuilder routeLocatorBuilder)
{
return routeLocatorBuilder.routes()
.route("login_page", rt -> rt.path("/login/**")
.filters(f -> f.removeRequestHeader("Cookie")
.removeRequestHeader("Set-Cookie"))
.uri(authorization_server))
.route("/oauth2_path", rt ->  rt.path("/oauth2/**")
.uri(authorization_server))
.route("tiktok_path", rt -> rt.path("/tiktok/**")
.uri(authorization_server))
.build();
}
}

Code: Select all

#application.yml
server:
port: 8080

spring:
web:
resources:
static-locations: classpath:/static/
security:
oauth2:
client:
registration:
gateway:
provider: spring
client-id: gateway
client-secret: secret
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
scope: openid,resource.read
provider:
spring:
issuer-uri: ${provider.issuer-uri}
resourceserver:
jwt:
issuer-uri: ${app.auth-server}

logging:
level:
root: INFO
org.springframework.security: trace
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator: INFO
org.springframework.cloud.gateway: trace
org.springframework.security.oauth2: trace

provider:
issuer-uri: http://localhost:9000

eureka:
defaultZoneUrl: http://u:p@localhost:8761/eureka/

app:
auth-server: http://localhost:9000
und pom.xml für Spring Cloud Gateway:

Code: Select all


4.0.0

org.springframework.boot
spring-boot-starter-parent
4.0.0
  

com.forum
auth2_cloud_gateway
0.0.1-SNAPSHOT
auth2_cloud_gateway
auth2_cloud_gateway


17
2025.1.0-RC1



org.springframework.boot
spring-boot-starter-security


org.springframework.boot
spring-boot-starter-security-oauth2-client


org.springframework.cloud
spring-cloud-starter-gateway-server-webflux



org.springframework.boot
spring-boot-starter-security-oauth2-client-test
test


org.springframework.boot
spring-boot-starter-security-test
test


io.projectreactor
reactor-test
test


org.springframework.security
spring-security-oauth2-resource-server






org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import







org.springframework.boot
spring-boot-maven-plugin





und Quellen des Spring-Autorisierungsservers:

Code: Select all

//AuthorizationServerApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AuthorizationServerApplication {

public static void main(String[] args) {
SpringApplication.run(AuthorizationServerApplication.class,  args);
}

}

//AuthorizationServerConfig.java
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
public class AuthorizationServerConfig {
private static final Logger LOG = LoggerFactory.getLogger(AuthorizationServerConfig.class);

@Value("${auth-provider.issuer-uri}")
private String issuer_uri;
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer();
authorizationServerConfigurer
.authorizationEndpoint(authorizationEndpoint ->
authorizationEndpoint
.authenticationProviders(configureAuthenticationValidator())
);
RequestMatcher endpointsMatcher = authorizationServerConfigurer
.getEndpointsMatcher();
http.securityMatcher(endpointsMatcher)
.authorizeHttpRequests(authorize ->{
authorize.requestMatchers("/oauth2").permitAll();
authorize.requestMatchers("/login").permitAll();
authorize.anyRequest().authenticated();
})
.apply(authorizationServerConfigurer);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0
http
.exceptionHandling(exceptions ->
exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(withDefaults()));
WebMvcAutoConfiguration a=null;
return http.build();
}

@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("gateway")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) // it was not heer
.redirectUri("http://localhost:8080/swagger-ui/index.html")
.scope(OidcScopes.OPENID)
.scope("resource.write")
.scope("resource.read")
.clientSettings(ClientSettings.builder().requireProofKey(false).build())
.tokenSettings(TokenSettings.builder()
.accessTokenTimeToLive(Duration.of(60*24*140, ChronoUnit.MINUTES))
.refreshTokenTimeToLive(Duration.of(120*24*140, ChronoUnit.MINUTES))
.build())
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}@Bean
public UserDetailsService users() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("admin")
.password("1")
.roles("ADMIN")
.build();

return new InMemoryUserDetailsManager(user);
}

@Bean
public JWKSet getJwkSet(){
RSAKey rsaKey = generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return jwkSet;
}
@Bean
public JWKSource jwkSource(JWKSet jwkSet) {

return (jwkSelector, securityContext) ->  jwkSelector.select(jwkSet);
}
@Bean
public JwtDecoder jwtDecoder(JWKSource jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
private static RSAKey generateRsa() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// delete next line if you can
System.out.println("Oper RSA key "+keyPair.getPublic() );
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
}

private static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().issuer(issuer_uri).build();
}
/* @Bean
public ProviderSettings providerSettings() {
return ProviderSettings.builder()
.issuer(issuer_uri) //"http://localhost:9000") ////
.build();
}*/

private Consumer configureAuthenticationValidator() {
return (authenticationProviders) ->
authenticationProviders.forEach((authenticationProvider) -> {
if (authenticationProvider instanceof OAuth2AuthorizationCodeRequestAuthenticationProvider) {
Consumer authenticationValidator =
// Override default redirect_uri validator
new CustomRedirectUriValidator()
// Reuse default scope validator
.andThen(OAuth2AuthorizationCodeRequestAuthenticationValidator.DEFAULT_SCOPE_VALIDATOR);

((OAuth2AuthorizationCodeRequestAuthenticationProvider) authenticationProvider)
.setAuthenticationValidator(authenticationValidator);
}
});
}
static class CustomRedirectUriValidator implements Consumer {

@Override
public void accept(OAuth2AuthorizationCodeRequestAuthenticationContext authenticationContext) {
OAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication =
authenticationContext.getAuthentication();
RegisteredClient registeredClient = authenticationContext.getRegisteredClient();
String requestedRedirectUri = authorizationCodeRequestAuthentication.getRedirectUri();

LOG.trace("Will validate the redirect uri {}", requestedRedirectUri);

// Use exact string matching when comparing client redirect URIs against pre-registered URIs
if (!registeredClient.getRedirectUris().contains(requestedRedirectUri)) {
LOG.trace("Redirect uri is invalid!");
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST);
//ithing i dont need it                throw new OAuth2AuthorizationCodeRequestAuthenticationException(error, null);  //i think i dont need IT
}
LOG.trace("Redirect uri is OK!");
}
}

@Bean //https://stackoverflow.com/questions/36809528/spring-boot-cors-filter-cors-preflight-channel-did-not-succeed
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
LOG.error("CorsConfigurationSource corsConfigurationSource");
return source;
}

@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000");
LOG.error("Cors Mapping from configurer");
}
};
}
}
//DefaultSecurityConfig.java

@Configuration
@EnableWebSecurity
public class DefaultSecurityConfig {
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(CsrfConfigurer::disable)
.authorizeHttpRequests(authorizeRequests -> {
authorizeRequests.requestMatchers("/index.html").permitAll();
authorizeRequests.requestMatchers("/favicon.ico").permitAll();
authorizeRequests.requestMatchers("/assets/**").permitAll();
authorizeRequests.requestMatchers("/jwks").permitAll();
authorizeRequests.requestMatchers("/oauth2").permitAll();
authorizeRequests.requestMatchers("/oauth2/**").permitAll();
authorizeRequests.requestMatchers("/login").permitAll();
authorizeRequests.requestMatchers("/**").permitAll();
authorizeRequests
.anyRequest()
.authenticated();
}
);
http
.formLogin(withDefaults());
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder PASSWORD_ENCODER = PasswordEncoderFactories.createDelegatingPasswordEncoder();
return PASSWORD_ENCODER;
}
}
//JwkKeyEndpoint.java
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

@RestController
public class JwkKeyEndpoint {
@Autowired
private JWKSet jwkSet;

@GetMapping("/jwks")
@ResponseBody
public String getKey() {
jwkSet.toPublicJWKSet().getKeys();
List  jwkValueList = jwkSet.toPublicJWKSet().getKeys();
return jwkValueList.get(0).toString();
}
}

Code: Select all

#application.yml
server:
port: 9000
logging:
level:
#root: TRACE
org.springframework.security: trace
application.localhost-path: localhost

auth-provider:
issuer-uri: "http://localhost:9000"
auth-server:
get-jwk-link: "http://localhost:9000/jwks"
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://${application.localhost-path}:9000
und pom.xml für den Spring-Autorisierungsserver:

Code: Select all


4.0.0


org.springframework.boot
spring-boot-starter-parent
4.0.0 
 


com.forum
authorization-server
0.0.1-SNAPSHOT
authorization-server
authorization-server


17
2025.0.0
7.0.0




org.springframework.boot
spring-boot-starter-security


org.springframework.boot
spring-boot-starter-web


org.springframework.security
spring-security-oauth2-authorization-server
${spring-auth-server.version}


org.springframework.boot
spring-boot-autoconfigure




org.springframework.boot
spring-boot-starter-test
test


org.springframework.security
spring-security-test
test



org.projectlombok
lombok
1.18.42
provided



org.postgresql
postgresql




org.hibernate
hibernate-core
7.0.10.Final 



io.jsonwebtoken
jjwt-api
0.12.6
    compile
 

io.jsonwebtoken
jjwt-impl
0.12.6
runtime


io.jsonwebtoken
jjwt-jackson
0.12.6
runtime



org.springframework.security
spring-security-config


commons-logging
commons-logging
1.3.5





org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import







org.springframework.boot
spring-boot-maven-plugin








Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post