View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.provisioning.api.utils;
20  
21  import java.util.Collection;
22  import java.util.HashSet;
23  import java.util.Optional;
24  import java.util.Set;
25  import java.util.function.Predicate;
26  import java.util.stream.Collectors;
27  import org.apache.commons.lang3.tuple.Pair;
28  import org.apache.syncope.common.lib.SyncopeConstants;
29  
30  public final class RealmUtils {
31  
32      public static String getGroupOwnerRealm(final String realmPath, final String groupKey) {
33          return realmPath + '@' + groupKey;
34      }
35  
36      public static Optional<Pair<String, String>> parseGroupOwnerRealm(final String input) {
37          String[] split = input.split("@");
38          return split == null || split.length < 2
39                  ? Optional.empty()
40                  : Optional.of(Pair.of(split[0], split[1]));
41      }
42  
43      public static boolean normalizingAddTo(final Set<String> realms, final String newRealm) {
44          boolean dontAdd = false;
45          Set<String> toRemove = new HashSet<>();
46          for (String realm : realms) {
47              if (newRealm.startsWith(realm)) {
48                  dontAdd = true;
49              } else if (realm.startsWith(newRealm)) {
50                  toRemove.add(realm);
51              }
52          }
53  
54          realms.removeAll(toRemove);
55          if (!dontAdd) {
56              realms.add(newRealm);
57          }
58          return !dontAdd;
59      }
60  
61      public static Pair<Set<String>, Set<String>> normalize(final Collection<String> realms) {
62          Set<String> normalized = new HashSet<>();
63          Set<String> groupOwnership = new HashSet<>();
64          if (realms != null) {
65              realms.forEach(realm -> {
66                  if (realm.indexOf('@') == -1) {
67                      normalizingAddTo(normalized, realm);
68                  } else {
69                      groupOwnership.add(realm);
70                  }
71              });
72          }
73  
74          return Pair.of(normalized, groupOwnership);
75      }
76  
77      private static class StartsWithPredicate implements Predicate<String> {
78  
79          private final Collection<String> targets;
80  
81          StartsWithPredicate(final Collection<String> targets) {
82              this.targets = targets;
83          }
84  
85          @Override
86          public boolean test(final String realm) {
87              return targets.stream().anyMatch(realm::startsWith);
88          }
89      }
90  
91      private static final Predicate<String> DYN_REALMS_PREDICATE = r -> !r.startsWith(SyncopeConstants.ROOT_REALM);
92  
93      public static Set<String> getEffective(final Set<String> allowedRealms, final String requestedRealm) {
94          Pair<Set<String>, Set<String>> normalized = normalize(allowedRealms);
95  
96          Set<String> requested = Set.of(requestedRealm);
97  
98          StartsWithPredicate normalizedFilter = new StartsWithPredicate(normalized.getLeft());
99          StartsWithPredicate requestedFilter = new StartsWithPredicate(requested);
100 
101         Set<String> effective = new HashSet<>();
102         effective.addAll(requested.stream().filter(normalizedFilter).collect(Collectors.toSet()));
103         effective.addAll(normalized.getLeft().stream().filter(requestedFilter).collect(Collectors.toSet()));
104 
105         // includes group ownership
106         effective.addAll(normalized.getRight());
107 
108         // includes dynamic realms
109         if (allowedRealms != null) {
110             effective.addAll(allowedRealms.stream().filter(DYN_REALMS_PREDICATE).collect(Collectors.toSet()));
111         }
112 
113         return effective;
114     }
115 
116     private RealmUtils() {
117         // empty constructor for static utility class 
118     }
119 }