View Javadoc
1   package cn.home1.cloud.config.server.security;
2   
3   import static cn.home1.cloud.config.server.util.Consts.DOT_ENV;
4   import static cn.home1.cloud.config.server.util.Consts.PRIVILEGE_ENV_PROFILE_;
5   import static java.util.stream.Collectors.toSet;
6   import static org.apache.commons.lang3.StringUtils.isNotEmpty;
7   
8   import lombok.Setter;
9   import lombok.extern.slf4j.Slf4j;
10  
11  import org.springframework.beans.factory.annotation.Autowired;
12  import org.springframework.security.core.Authentication;
13  import org.springframework.security.core.GrantedAuthority;
14  import org.springframework.security.core.context.SecurityContextHolder;
15  
16  import java.util.Collection;
17  import java.util.Optional;
18  import java.util.regex.Pattern;
19  
20  /**
21   * Determine whether let user go further by login user and repository name in URL.
22   */
23  @Slf4j
24  public class ApplicationConfigSecurity {
25  
26      private static final Pattern PATTERN_COMMA = Pattern.compile(",");
27  
28      @Autowired
29      @Setter
30      private PrivilegedUserProperties privilegedUserProperties;
31  
32      /**
33       * Allow admin user, allow user that name matches repository name
34       *
35       * @param pathApplication application (repository) name extracted from path
36       * @param pathProfiles    profiles extracted from path
37       * @return allow access
38       */
39      public boolean checkAuthentication(final String pathApplication, final String pathProfiles) {
40          final boolean result;
41  
42          final Collection<String> envProfiles = PATTERN_COMMA.splitAsStream(pathProfiles)
43              .filter(profile -> profile.endsWith(DOT_ENV))
44              .collect(toSet());
45  
46          final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
47          final String authName = auth != null ? auth.getName() : null;
48  
49          if (envProfiles.size() <= 1) {
50              if (isNotEmpty(authName) && auth.isAuthenticated()) {
51                  final String adminName = this.privilegedUserProperties.getAdminName();
52                  if (adminName.equals(authName)) {
53                      result = true;
54                  } else {
55                      final boolean applicationMatch = pathApplication != null && pathApplication.equals(authName);
56                      final boolean isRequestValid = this.isRequestValid(auth, envProfiles);
57                      result = applicationMatch && isRequestValid;
58                  }
59              } else {
60                  result = false;
61              }
62          } else {
63              result = false;
64              log.info("Illegal to access multiple environment profiles ({}) in one request", envProfiles);
65          }
66  
67          log.debug("'{}' {} privilege to access '{}'", authName, result ? "has" : "has no", pathApplication);
68          return result;
69      }
70  
71      boolean isRequestValid(final Authentication auth, final Collection<String> envProfiles) {
72          final boolean result;
73  
74          final Optional<String> privilege = auth.getAuthorities().stream()
75              .map(GrantedAuthority::getAuthority)
76              .filter(authority -> authority.startsWith(PRIVILEGE_ENV_PROFILE_))
77              .map(p -> p.replace(PRIVILEGE_ENV_PROFILE_, ""))
78              .findFirst(); // one environment profile privilege at most, may be none.
79  
80          if (privilege.isPresent() && privilege.get().equals("*")) {
81              result = true; // wildcard privilege can access any environment profile
82          } else {
83              result = privilege
84                  .map(p -> envProfiles.isEmpty() || envProfiles.contains(p)) // access no or matched environment profile only
85                  .orElseGet(envProfiles::isEmpty); // can not access any environment profile
86          }
87  
88          return result;
89      }
90  }