1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.sra.security;
20
21 import java.util.Map;
22 import java.util.Optional;
23 import java.util.concurrent.ConcurrentHashMap;
24 import org.apache.syncope.sra.RouteProvider;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27 import org.springframework.beans.factory.annotation.Autowired;
28 import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
29 import org.springframework.cloud.gateway.route.Route;
30 import org.springframework.cloud.gateway.route.RouteLocator;
31 import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
32 import org.springframework.context.ApplicationListener;
33 import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
34 import org.springframework.web.server.ServerWebExchange;
35 import reactor.core.publisher.Mono;
36
37 public abstract class AbstractRouteMatcher
38 implements ServerWebExchangeMatcher, ApplicationListener<RefreshRoutesEvent> {
39
40 private static final Logger LOG = LoggerFactory.getLogger(AbstractRouteMatcher.class);
41
42 protected static final Map<String, Map<String, Boolean>> CACHE = new ConcurrentHashMap<>();
43
44 @Autowired
45 private RouteLocator routeLocator;
46
47 @Autowired
48 protected RouteProvider routeProvider;
49
50 protected abstract String getCacheName();
51
52 protected abstract boolean routeBehavior(Route route);
53
54 @Override
55 public void onApplicationEvent(final RefreshRoutesEvent event) {
56 Optional.ofNullable(CACHE.get(getCacheName())).ifPresent(Map::clear);
57 }
58
59 @Override
60 public Mono<MatchResult> matches(final ServerWebExchange exchange) {
61
62 return routeLocator.getRoutes().
63
64 concatMap(route -> Mono.just(route).filterWhen(r -> r.getPredicate().apply(exchange)).
65
66 doOnError(e -> LOG.error("Error applying predicate for route: {}", route.getId(), e)).
67 onErrorResume(e -> Mono.empty())).
68 next().
69 flatMap(route -> {
70 exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, route.getId());
71 LOG.debug("[{}] Route found: {}", getClass().getName(), route);
72
73 boolean cond = Optional.ofNullable(CACHE.get(getCacheName()).get(route.getId())).orElseGet(() -> {
74 boolean result = routeBehavior(route);
75 CACHE.get(getCacheName()).put(route.getId(), result);
76 return result;
77 });
78 LOG.debug("[{}] Condition matched: {}", getClass().getName(), cond);
79
80 return cond ? MatchResult.match() : MatchResult.notMatch();
81 }).switchIfEmpty(Mono.defer(() -> {
82 LOG.debug("[{}] No Route found", getClass().getName());
83 return MatchResult.notMatch();
84 }));
85 }
86 }