Code development platform for open source projects from the European Union institutions :large_blue_circle: EU Login authentication by SMS has been phased out. To see alternatives please check here

Skip to content
Snippets Groups Projects
Commit 965ff0de authored by Marco Amoia's avatar Marco Amoia
Browse files

Merge branch 'release' into 'main'

Release 1.1.0

See merge request simpl/simpl-open/development/iaa/simpl-cloud-gateway!76
parents 2e7c91ae dcacb620
Branches
Tags v1.1.0
2 merge requests!77Update version to 1.2.0,!76Release 1.1.0
Pipeline #270571 failed
# ConfigMap Configuration
This `ConfigMap` is designed to configure a Kubernetes application based on different profiles and environmental variables. The `ConfigMap` is templated using Helm, allowing customization based on the values provided in the Helm chart.
## Overview
The `ConfigMap` is used to store non-confidential configuration data in key-value pairs. This configuration supports two main profiles: `authority` and `participant`. Depending on the profile specified in the Helm chart, different environment variables will be set.
## Configuration Details
### Profiles
- **Authority Profile**
- If the global profile is set to `authority`, the following environment variable is configured:
- `SAP_URL`: URL for the Security Attributes Provider.
- Format: `http://security-attributes-provider.<namespace>.svc.cluster.local:8080`
- `ONBOARDING_URL`: URL for the Onboarding.
- Format: `http://onboarding.<namespace>.svc.cluster.local:8080`
- `EJBCA_URL`: URL for the EJBCA.
- Format: `http://ejbca-community-helm.<namespace>.svc.cluster.local:30080`
- `IDENTITY_PROVIDER_URL`: URL for the Identity Provider.
- Format: `http://identity-provider.<namespace>.svc.cluster.local:8080`
- **Participant Profile**
- If the global profile is set to `participant`, the following environment variable is configured:
- `AUTHORITY_URL`: URL of the authority backend.
- Value is derived from the `global.authorityUrl` specified in the Helm values.
### Common Configuration
Regardless of the profile, the following environment variables are configured:
- `SPRING_PROFILES_ACTIVE`: This sets the active Spring profile.
- Value is derived from the `global.profile` specified in the Helm values.
- `CORS_ALLOWED_HEADERS`: Specifies which HTTP headers are allowed in cross-origin requests.
- Default value: `Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Access-Control-Allow-Origin, Access-Control-Allow-Methods, Keep-Alive, User-Agent, Content-Type, Authorization, Tenant, Channel, Platform, Set-Cookie, geolocation, x-mobility-mode, device, Cache-Control, X-Request-With, Accept, Origin`.
- `CORS_ALLOWED_ORIGINS`: Specifies which origins are allowed to make cross-origin requests.
- Value is derived from `global.cors.allowOrigin` specified in the Helm values.
- `KEYCLOAK_URL`: The URL for the Keycloak authentication service.
- This value is generated using the `miroservices.keycloakUrl` specified in the Helm values.
- `USERSROLES_URL`: The URL for the Users&Roles service.
- This value is generated using the `miroservices.usersRolesUrl` specified in the Helm values.
## Usage
To use this `ConfigMap`, include it in your Helm chart and provide the necessary values in the `values.yaml` file. The `ConfigMap` will be generated based on the profile and other settings you define.
### Example `values-global.yaml`
```yaml
global:
profile: participant / authority
hostBe: authority.be.aruba-simpl.cloud
hostTls: tls.authority.aruba-simpl.cloud
authorityUrl: "https://authority-service.example.com"
ingress:
issuer: yourIngressIssuer
cors:
allowOrigin: "https://example.com"
```
### Example `values-authority.yaml`
```yaml
microservices:
usersRolesUrl: http://users-roles.{{ .Release.Namespace }}.svc.cluster.local:8080
securityAttributesProviderUrl: http://security-attributes-provider.{{ .Release.Namespace }}.svc.cluster.local:8080
keycloakUrl: http://keycloak.{{ .Release.Namespace }}.svc.cluster.local
onboardingUrl: http://onboarding.{{ .Release.Namespace }}.svc.cluster.local:8080
ejbcaUrl: http://ejbca-community-helm.{{ .Release.Namespace }}.svc.cluster.local:30080
identityProviderUrl: http://identity-provider.{{ .Release.Namespace }}.svc.cluster.local:8080
```
### Example `values-participant.yaml`
```yaml
microservices:
usersRolesUrl: http://users-roles.{{ .Release.Namespace }}.svc.cluster.local:8080
keycloakUrl: http://keycloak.{{ .Release.Namespace }}.svc.cluster.local
```
## Gateway Routes Configuration
To configure the internal routes of the gateway, you need to modify the `routes`
variable in the `values.yaml` file. This variable allows you to define routing
rules that the gateway will follow to connect to various internal services.
### Routes Configuration
Here is an example of how to configure the routes for the gateway:
```yaml
# Spring Cloud Gateway Routes Authority
springRoutes:
- id: keycloak
uri: ${keycloak.url}
predicates:
- Path=/auth/**
filters:
- StripPrefix=1
- id: users-roles
uri: ${users-roles.url}
predicates:
- Path=/*/user-api/**
filters:
- StripPrefix=2
- id: onboarding
uri: ${onboarding.url}
predicates:
- Path=/*/onboarding-api/**
filters:
- StripPrefix=2
- id: sap
uri: ${sap.url}
predicates:
- Path=/*/sap-api/**
filters:
- StripPrefix=2
- id: identity-provider
uri: ${identity-provider.url}
predicates:
- Path=/*/identity-api/**
filters:
- StripPrefix=2
- id: ocsp
uri: ${ejbca.url}
predicates:
- Path=/ocsp
filters:
- RewritePath=/ocsp/*, /ejbca/publicweb/status/ocsp
- id: ca-certificates
uri: ${ejbca.url}
predicates:
- Path=/ca/*
filters:
- RewritePath=/ca/?(?<segment>.*), /ejbca/publicweb/webdist/certdist?cmd=cacert&issuer=CN%3D$\{segment}
- id: crl
uri: ${ejbca.url}
predicates:
- Path=/crl/*
filters:
- RewritePath=/crl/?(?<segment>.*), /ejbca/publicweb/webdist/certdist?cmd=crl&issuer=CN%3D$\{segment}
```
```yaml
# Spring Cloud Gateway Routes Participant
springRoutes:
- id: keycloak
uri: ${keycloak.url}
predicates:
- Path=/auth/**
filters:
- StripPrefix=1
- id: users-roles
uri: ${users-roles.url}
predicates:
- Path=/*/user-api/**
filters:
- StripPrefix=2
```
### Swagger configuration
Additionally, the `swaggerUrls` variable enables you to configure API documentation
using OpenAPI/Swagger.
## Authority
```yaml
swaggerUrls:
- url: /sap-api/v3/api-docs
name: Security Attributes Provider Service
- url: /onboarding-api/v3/api-docs
name: Onboarding Service
- url: /user-api/v3/api-docs
name: Users & Roles Service
- url: /identity-api/v3/api-docs
name: Identity Provider Service
```
## Participant
```yaml
swaggerUrls:
- url: /user-api/v3/api-docs
name: Users & Roles Service
```
### Custom Role Based Access Control
```yaml
routes:
publicUrls:
- method: GET
path: "public"
deniedUrls:
- method: GET
path: "todeny"
rbac:
- path: "rbacPath"
roles:
- NOTARY
- T1UAR_M
```
\ No newline at end of file
PROJECT_VERSION_NUMBER="1.0.1" PROJECT_VERSION_NUMBER="1.1.0"
\ No newline at end of file \ No newline at end of file
...@@ -5,12 +5,12 @@ ...@@ -5,12 +5,12 @@
<parent> <parent>
<groupId>eu.europa.ec.simpl</groupId> <groupId>eu.europa.ec.simpl</groupId>
<artifactId>simpl-parent</artifactId> <artifactId>simpl-parent</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<artifactId>gatewayserver</artifactId> <artifactId>gatewayserver</artifactId>
<version>1.0.1</version> <version>1.1.0</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>gateway-server</name> <name>gateway-server</name>
......
package eu.europa.ec.simpl.gatewayserver.filters;
import com.nimbusds.jwt.SignedJWT;
import eu.europa.ec.simpl.common.constants.SimplHeaders;
import eu.europa.ec.simpl.common.exceptions.InvalidTierOneSessionException;
import eu.europa.ec.simpl.common.exceptions.TierOneTokenNotFound;
import eu.europa.ec.simpl.common.utils.JwtUtil;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Component
public class HeadersFilter implements WebFilter {
private static final Logger log = LoggerFactory.getLogger(HeadersFilter.class);
private final String rolesClaimName;
public HeadersFilter(
@Value("${spring.security.oauth2.resourceserver.jwt.authorities-claim-name}") String rolesClaimName) {
this.rolesClaimName = rolesClaimName;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
if (shouldSkip(exchange)) {
return chain.filter(exchange);
}
return parseToken(exchange)
.flatMap(jwt -> addHeadersToRequest(exchange, jwt))
.flatMap(chain::filter); // Continue the filter chain after adding auth info
}
private boolean shouldSkip(ServerWebExchange exchange) {
return exchange.getRequest().getPath().value().startsWith("/auth")
|| !exchange.getRequest().getHeaders().containsKey(HttpHeaders.AUTHORIZATION);
}
@SneakyThrows
private Mono<ServerWebExchange> addHeadersToRequest(ServerWebExchange exchange, SignedJWT jwt) {
log.debug("Adding JWT claims to request");
var claimSet = JwtUtil.getClaimSet(jwt);
List<String> roles =
Objects.requireNonNullElse(JwtUtil.getListClaim(jwt, rolesClaimName, String.class), new ArrayList<>());
ServerHttpRequest mutatedRequest = exchange.getRequest()
.mutate()
.header(SimplHeaders.USERNAME, claimSet.getStringClaim("preferred_username"))
.header(SimplHeaders.USER_EMAIL, claimSet.getStringClaim("email"))
.header(SimplHeaders.USER_ID, claimSet.getSubject())
.header(SimplHeaders.USER_ROLES, String.join(",", roles))
.build();
return Mono.just(exchange.mutate().request(mutatedRequest).build());
}
private Mono<SignedJWT> parseToken(ServerWebExchange exchange) {
var token = JwtUtil.getBearerToken(exchange.getRequest().getHeaders()).orElseThrow(TierOneTokenNotFound::new);
return Mono.fromCallable(() -> {
try {
return SignedJWT.parse(token);
} catch (ParseException e) {
throw new InvalidTierOneSessionException();
}
});
}
}
...@@ -10,6 +10,7 @@ import eu.simpl.types.MessageType; ...@@ -10,6 +10,7 @@ import eu.simpl.types.MessageType;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.lookup.StrSubstitutor; import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse;
...@@ -108,7 +109,7 @@ public class LoggingFilter implements WebFilter { ...@@ -108,7 +109,7 @@ public class LoggingFilter implements WebFilter {
return Optional.of(exchange.getResponse()) return Optional.of(exchange.getResponse())
.map(ServerHttpResponse::getStatusCode) .map(ServerHttpResponse::getStatusCode)
.map(Objects::toString) .map(Objects::toString)
.orElse(""); .orElse(StringUtils.EMPTY);
} }
} }
} }
......
...@@ -14,30 +14,60 @@ spring: ...@@ -14,30 +14,60 @@ spring:
- Path=/user-api/** - Path=/user-api/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
- id: users-rolesV1
uri: ${users-roles.url}
predicates:
- Path=/userApi/**
filters:
- StripPrefix=1
- id: onboarding - id: onboarding
uri: ${onboarding.url} uri: ${onboarding.url}
predicates: predicates:
- Path=/onboarding-api/** - Path=/onboarding-api/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
- id: onboardingV1
uri: ${onboarding.url}
predicates:
- Path=/onboardingApi/**
filters:
- StripPrefix=1
- id: sap - id: sap
uri: ${sap.url} uri: ${sap.url}
predicates: predicates:
- Path=/sap-api/** - Path=/sap-api/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
- id: sapV1
uri: ${sap.url}
predicates:
- Path=/sapApi/**
filters:
- StripPrefix=1
- id: identity-provider - id: identity-provider
uri: ${identity-provider.url} uri: ${identity-provider.url}
predicates: predicates:
- Path=/identity-api/** - Path=/identity-api/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
- id: identity-providerV1
uri: ${identity-provider.url}
predicates:
- Path=/identityApi/**
filters:
- StripPrefix=1
- id: authentication-provider - id: authentication-provider
uri: ${authentication-provider.url} uri: ${authentication-provider.url}
predicates: predicates:
- Path=/auth-api/** - Path=/auth-api/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
- id: authentication-providerV1
uri: ${authentication-provider.url}
predicates:
- Path=/authApi/**
filters:
- StripPrefix=1
- id: ocsp - id: ocsp
uri: ${ejbca.url} uri: ${ejbca.url}
predicates: predicates:
...@@ -57,44 +87,57 @@ spring: ...@@ -57,44 +87,57 @@ spring:
filters: filters:
- RewritePath=/crl/?(?<segment>.*), /ejbca/publicweb/webdist/certdist?cmd=crl&issuer=CN%3D$\{segment} - RewritePath=/crl/?(?<segment>.*), /ejbca/publicweb/webdist/certdist?cmd=crl&issuer=CN%3D$\{segment}
# Cli configurations # Cli configurations
- id: cli-authentication-provider - id: cli-authentication-providerV1
uri: ${authentication-provider.url} uri: ${authentication-provider.url}
predicates: predicates:
- Path=/cli/auth-api/csr/generate,/cli/auth-api/keypair/generate,/cli/auth-api/keypair - Path=
/cli/authApi/v1/csr/generate,
/cli/authApi/v1/keypairs/generate,
/cli/authApi/v1/keypairs,
/cli/authApi/v1/credentials,
/cli/authApi/v1/credentials/download,
/cli/authApi/v1/agent/ping
filters: filters:
- StripPrefix=2 - StripPrefix=2
- name: ClientCredentialsFilter - name: ClientCredentialsFilter
args: args:
#clientid: requiredRole1,requiredRole2 #clientid: requiredRole1,requiredRole2
cli: cli-role cli: cli-role
- id: cli-identity-providerV1
- id: cli-identity-provider
uri: ${identity-provider.url} uri: ${identity-provider.url}
predicates: predicates:
- Path=/cli/identity-api/csr/store/*,/cli/identity-api/participant/from-cli,/cli/identity-api/certificate/* - Path=
/cli/identityApi/v1/participants/*/csr,
/cli/identityApi/v1/participants,
/cli/identityApi/v1/participants/authorityExists,
/cli/identityApi/v1/credentials/*/download
filters: filters:
- StripPrefix=2 - StripPrefix=2
- name: ClientCredentialsFilter - name: ClientCredentialsFilter
args: args:
#clientid: requiredRole1,requiredRole2 #clientid: requiredRole1,requiredRole2
cli: cli-role cli: cli-role
- id: cli-security-attributes-providerV1
- id: cli-security-attributes-provider
uri: ${sap.url} uri: ${sap.url}
predicates: predicates:
- Path=/cli/sap-api/identity-attribute/store/import,/cli/sap-api/identity-attribute/add-participant-type/* - Path=
/cli/sapApi/v1/identityAttributes/import,
/cli/sapApi/v1/identityAttributes/addParticipantType/*
filters: filters:
- StripPrefix=2 - StripPrefix=2
- name: ClientCredentialsFilter - name: ClientCredentialsFilter
args: args:
#clientid: requiredRole1,requiredRole2 #clientid: requiredRole1,requiredRole2
cli: cli-role cli: cli-role
- id: cli-users-and-rolesV1
- id: cli-users-and-roles
uri: ${users-roles.url} uri: ${users-roles.url}
predicates: predicates:
- Path=/cli/user-api/user/import,/cli/user-api/role/import,/cli/user-api/role/*/identity-attributes - Path=
/cli/userApi/v1/users/import,
/cli/userApi/v1/roles/import,
/cli/userApi/v1/roles/*/identityAttributes
filters: filters:
- StripPrefix=2 - StripPrefix=2
- name: ClientCredentialsFilter - name: ClientCredentialsFilter
...@@ -103,6 +146,7 @@ spring: ...@@ -103,6 +146,7 @@ spring:
cli: cli-role cli: cli-role
springdoc: springdoc:
swagger-ui: swagger-ui:
urls: urls:
......
...@@ -20,23 +20,30 @@ spring: ...@@ -20,23 +20,30 @@ spring:
- Path=/auth-api/** - Path=/auth-api/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
# Cli configurations # Cli configurations
- id: cli-authentication-provider - id: cli-authentication-providerV1
uri: ${authentication-provider.url} uri: ${authentication-provider.url}
predicates: predicates:
- Path=/cli/auth-api/csr/generate,/cli/auth-api/keypair/generate,/cli/auth-api/keypair - Path=
/cli/authApi/v1/csr/generate,
/cli/authApi/v1/keypairs/generate,
/cli/authApi/v1/keypairs,
/cli/authApi/v1/credentials,
/cli/authApi/v1/credentials/download,
/cli/authApi/v1/agent/ping
filters: filters:
- StripPrefix=2 - StripPrefix=2
- name: ClientCredentialsFilter - name: ClientCredentialsFilter
args: args:
#clientid: requiredRole1,requiredRole2 #clientid: requiredRole1,requiredRole2
cli: cli-role cli: cli-role
- id: cli-users-and-rolesV1
- id: cli-users-and-roles
uri: ${users-roles.url} uri: ${users-roles.url}
predicates: predicates:
- Path=/cli/user-api/user/import,/cli/user-api/role/import,/cli/user-api/role/*/identity-attributes - Path=
/cli/userApi/v1/users/import,
/cli/userApi/v1/roles/import,
/cli/userApi/v1/roles/*/identityAttributes
filters: filters:
- StripPrefix=2 - StripPrefix=2
- name: ClientCredentialsFilter - name: ClientCredentialsFilter
......
package eu.europa.ec.simpl.gatewayserver.filters;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import eu.europa.ec.simpl.common.constants.SimplHeaders;
import eu.europa.ec.simpl.common.exceptions.InvalidTierOneSessionException;
import eu.europa.ec.simpl.common.utils.JwtUtil;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@ExtendWith(MockitoExtension.class)
class HeadersFilterTest {
private HeadersFilter headersFilter;
@Mock
private WebFilterChain filterChain;
@BeforeEach
void setUp() {
headersFilter = new HeadersFilter("client-roles");
}
@Test
void testFilterSkipsAuthEndpoints() {
when(filterChain.filter(any())).thenReturn(Mono.empty());
var request = MockServerHttpRequest.get("/auth/some-endpoint")
.header(HttpHeaders.AUTHORIZATION, "Bearer token")
.build();
var exchange = MockServerWebExchange.from(request);
StepVerifier.create(headersFilter.filter(exchange, filterChain)).verifyComplete();
verify(filterChain, times(1)).filter(exchange);
verifyNoMoreInteractions(filterChain);
}
@Test
void testFilterSkipsRequestsWithoutAuthorizationHeader() {
when(filterChain.filter(any())).thenReturn(Mono.empty());
var request = MockServerHttpRequest.get("/api/data").build();
var exchange = MockServerWebExchange.from(request);
StepVerifier.create(headersFilter.filter(exchange, filterChain)).verifyComplete();
verify(filterChain, times(1)).filter(exchange);
verifyNoMoreInteractions(filterChain);
}
@Test
void testFilterAddsHeadersForValidToken() {
when(filterChain.filter(any())).thenReturn(Mono.empty());
var token = "valid.jwt.token";
var request = MockServerHttpRequest.get("/api/data")
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
.build();
var exchange = MockServerWebExchange.from(request);
var jwt = mock(SignedJWT.class);
var claimsSet = new JWTClaimsSet.Builder()
.subject("user123")
.claim("preferred_username", "username")
.claim("email", "test@mail.com")
.claim("client-roles", Arrays.asList("ROLE_1", "ROLE_2"))
.build();
try (var jwtUtilMock = mockStatic(JwtUtil.class);
var signedJWTMock = mockStatic(SignedJWT.class)) {
jwtUtilMock
.when(() -> JwtUtil.getBearerToken(any(HttpHeaders.class)))
.thenReturn(Optional.of(token));
jwtUtilMock.when(() -> JwtUtil.getClaimSet(any())).thenReturn(claimsSet);
jwtUtilMock
.when(() -> JwtUtil.getListClaim(any(), eq("client-roles"), eq(String.class)))
.thenReturn(Arrays.asList("ROLE_1", "ROLE_2"));
signedJWTMock.when(() -> SignedJWT.parse(token)).thenReturn(jwt);
// Run the filter and verify it completes without errors
StepVerifier.create(headersFilter.filter(exchange, filterChain)).verifyComplete();
verify(filterChain).filter(any(ServerWebExchange.class));
// Capture the modified exchange to verify headers
var exchangeCaptor = ArgumentCaptor.forClass(ServerWebExchange.class);
verify(filterChain).filter(exchangeCaptor.capture());
var modifiedExchange = exchangeCaptor.getValue();
var headers = modifiedExchange.getRequest().getHeaders();
assert Objects.equals(headers.getFirst(SimplHeaders.USERNAME), "username");
assert Objects.equals(headers.getFirst(SimplHeaders.USER_EMAIL), "test@mail.com");
assert Objects.equals(headers.getFirst(SimplHeaders.USER_ID), "user123");
assert Objects.equals(headers.getFirst(SimplHeaders.USER_ROLES), "ROLE_1,ROLE_2");
}
}
@Test
void testFilterHandlesInvalidToken() {
var token = "invalid.jwt.token";
var request = MockServerHttpRequest.get("/api/data")
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
.build();
var exchange = MockServerWebExchange.from(request);
try (var jwtUtilMock = mockStatic(JwtUtil.class);
var signedJWTMock = mockStatic(SignedJWT.class)) {
jwtUtilMock
.when(() -> JwtUtil.getBearerToken(any(HttpHeaders.class)))
.thenReturn(Optional.of(token));
signedJWTMock.when(() -> SignedJWT.parse(token)).thenThrow(ParseException.class);
StepVerifier.create(headersFilter.filter(exchange, filterChain))
.expectError(InvalidTierOneSessionException.class)
.verify();
verify(filterChain, never()).filter(any(ServerWebExchange.class));
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment