View Javadoc
1   package cn.home1.cloud.config.server.environment;
2   
3   import static com.google.common.collect.Sets.newLinkedHashSet;
4   import static org.apache.commons.lang3.StringUtils.isBlank;
5   import static org.apache.commons.lang3.StringUtils.isNotBlank;
6   
7   import cn.home1.cloud.config.server.security.ConfigSecurity;
8   import cn.home1.cloud.config.server.util.EnvironmentUtils;
9   
10  import lombok.Setter;
11  import lombok.extern.slf4j.Slf4j;
12  
13  import org.springframework.boot.context.properties.ConfigurationProperties;
14  import org.springframework.cloud.config.environment.Environment;
15  import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository;
16  import org.springframework.core.env.ConfigurableEnvironment;
17  import org.springframework.security.authentication.BadCredentialsException;
18  
19  import java.util.Set;
20  
21  @ConfigurationProperties("spring.cloud.config.server.git")
22  @Slf4j
23  public class GitParentSupportMultipleJGitEnvironmentRepository extends MultipleJGitEnvironmentRepository {
24  
25      @Setter
26      private ConfigSecurity configSecurity;
27  
28      public GitParentSupportMultipleJGitEnvironmentRepository(final ConfigurableEnvironment environment) {
29          super(environment);
30      }
31  
32      @Override
33      public Environment findOne(final String application, final String profile, final String label) {
34          final Environment currentApplicationEnv = super.findOne(application, profile, label);
35  
36          // load parents
37          final Set<String> history = newLinkedHashSet();
38          history.add(EnvironmentUtils.getApplicationName(currentApplicationEnv));
39  
40          for (Environment parentEnv, applicationEnv = currentApplicationEnv; //
41               (parentEnv = getParentEnvironment(applicationEnv, label)) != null; //
42               applicationEnv = parentEnv) {
43  
44              final String parentApplication = EnvironmentUtils.getParentApplication(applicationEnv);
45  
46              final String expectedParentPassword = EnvironmentUtils.getConfigPassword(parentEnv);
47              if (isNotBlank(expectedParentPassword)) {
48                  final String token = EnvironmentUtils.getParentConfigPassword(applicationEnv);
49                  final Boolean hasParentPrivilege = this.configSecurity.verifyParentPassword(application, parentApplication, token, expectedParentPassword);
50                  if (!hasParentPrivilege) {
51                      throw new BadCredentialsException("Invalid access to parent config '" + parentApplication + "'.");
52                  }
53              }
54  
55              if (history.contains(parentApplication)) {
56                  log.warn("circular reference detected! ignore existed parent. application:{}, circular parentApplication:{}",
57                      application, parentApplication);
58                  break;
59              } else {
60                  history.add(parentApplication);
61              }
62  
63              // application config first.
64              // PropertySources[n] will override (cover) the value in PropertySources[n+1] under same key.
65              currentApplicationEnv.getPropertySources().addAll(parentEnv.getPropertySources());
66          }
67  
68          return currentApplicationEnv;
69      }
70  
71  
72      private Environment getParentEnvironment(final Environment environment, final String label) {
73          final String parentApplication = EnvironmentUtils.getParentApplication(environment);
74          if (parentApplication == null || isBlank(parentApplication)) {
75              return null;
76          }
77          final String parentLabel = EnvironmentUtils.getParentLabel(environment, label);
78  
79          Environment result = null;
80  
81          String[] profiles = environment.getProfiles();
82          if (profiles == null || profiles.length == 0) {
83              profiles = new String[]{"default"};
84          }
85  
86          for (final String profile : profiles) {
87              Environment found;
88              try {
89                  found = super.findOne(parentApplication, profile, parentLabel);
90              } catch (final Exception exception) {
91                  log.warn("error fetch parent exception! parentApplication:{}, profile:{}, parentLabel:{}",
92                      parentApplication, profile, parentLabel, exception);
93                  throw exception;
94              }
95  
96              if (result == null) {
97                  result = found;
98              } else {
99                  result.getPropertySources().addAll(found.getPropertySources());
100             }
101         }
102         return result;
103     }
104 }