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 cn.home1.cloud.config.server.util.Consts.PRIVILEGE_ENV_PROFILE_WILDCARD;
6 import static cn.home1.cloud.config.server.util.EnvironmentUtils.getConfigPassword;
7 import static java.util.stream.Collectors.toList;
8
9 import com.google.common.collect.ImmutableList;
10
11 import lombok.Setter;
12 import lombok.extern.slf4j.Slf4j;
13
14 import org.springframework.cloud.config.environment.Environment;
15 import org.springframework.cloud.config.server.environment.EnvironmentController;
16 import org.springframework.security.authentication.BadCredentialsException;
17 import org.springframework.security.core.GrantedAuthority;
18 import org.springframework.security.core.authority.SimpleGrantedAuthority;
19 import org.springframework.security.core.userdetails.User;
20 import org.springframework.security.core.userdetails.UserDetails;
21 import org.springframework.security.core.userdetails.UserDetailsService;
22 import org.springframework.security.core.userdetails.UsernameNotFoundException;
23
24 import java.util.Collection;
25 import java.util.Iterator;
26 import java.util.Optional;
27 import java.util.regex.Pattern;
28
29
30
31
32 @Slf4j
33 public class GitFileConfigUserDetailsService implements UserDetailsService {
34
35 private static final Pattern PATTERN_AT = Pattern.compile("@");
36
37 private static final Collection<? extends GrantedAuthority> ANONYMOUS_AUTHORITY = ImmutableList.of();
38
39 private static final Collection<? extends GrantedAuthority> HOOK_AUTHORITY =
40 ImmutableList.of(new SimpleGrantedAuthority("ROLE_" + Role.HOOK.toString()));
41
42 private static final GrantedAuthority USER_AUTHORITY = new SimpleGrantedAuthority(
43 "ROLE_" + Role.USER.toString());
44
45 @Setter
46 private ConfigSecurity configSecurity;
47
48 @Setter
49 private String defaultLabel;
50
51 @Setter
52 private EnvironmentController environmentController;
53
54 @Setter
55 private PrivilegedUserProperties privilegedUserProperties;
56
57 @Override
58 public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
59 if (username == null) {
60 return new User("anonymous", "", ANONYMOUS_AUTHORITY);
61 }
62
63 if (username.equals(this.privilegedUserProperties.getAdminName())) {
64 final Collection<? extends GrantedAuthority> adminAuthority = this.privilegedUserProperties.getAdminRoles()
65 .stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).collect(toList());
66 return new User(username, this.privilegedUserProperties.getAdminPassword(), adminAuthority);
67 }
68
69 if (username.equals(this.privilegedUserProperties.getHookName())) {
70 return new User(username, this.privilegedUserProperties.getHookPassword(), HOOK_AUTHORITY);
71 }
72
73
74 final String application;
75 final String profileToAuth;
76 final Optional<GrantedAuthority> privilege;
77 if (username.contains("@") && username.endsWith(DOT_ENV)) {
78 final Iterator<String> parts = PATTERN_AT.splitAsStream(username).iterator();
79 application = parts.next();
80 profileToAuth = parts.next();
81 privilege = Optional.of(new SimpleGrantedAuthority(PRIVILEGE_ENV_PROFILE_ + profileToAuth));
82 } else if (username.endsWith("@default")) {
83 final Iterator<String> parts = PATTERN_AT.splitAsStream(username).iterator();
84 application = parts.next();
85 profileToAuth = parts.next();
86 privilege = Optional.empty();
87 } else {
88 application = username;
89 profileToAuth = "default";
90 privilege = Optional.of(new SimpleGrantedAuthority(PRIVILEGE_ENV_PROFILE_WILDCARD));
91 }
92 final Collection<GrantedAuthority> authorities = privilege.isPresent() ?
93 ImmutableList.of(USER_AUTHORITY, privilege.get()) : ImmutableList.of(USER_AUTHORITY);
94
95
96 final String expectedPassword = this.findExpectedPassword(application, profileToAuth);
97 if (expectedPassword == null) {
98 throw new BadCredentialsException(
99 "can not find 'spring.cloud.config.password' application: " + application + ", profile: " + profileToAuth);
100 }
101 final String rawExpectedPassword = this.configSecurity.decryptProperty(expectedPassword);
102
103 return new User(application, rawExpectedPassword, authorities);
104 }
105
106 String findExpectedPassword(final String application, final String profile) {
107 final String result;
108
109 if (this.defaultLabel != null) {
110 final String found = this.findExpectedPassword(application, profile, this.defaultLabel);
111 result = found != null ? found : this.findExpectedPassword(application, profile, null);
112 } else {
113 result = this.findExpectedPassword(application, profile, null);
114 }
115
116 return result;
117 }
118
119 String findExpectedPassword(final String application, final String profile, final String label) {
120 final Environment environment;
121
122 try {
123 environment = this.environmentController.labelled(application, profile, label);
124 } catch (final Exception exception) {
125 log.warn("error on loadUserByUsername from git configuration file, username: {}",
126 application, exception);
127 throw exception;
128 }
129
130 if (environment == null) {
131 throw new UsernameNotFoundException("can not find the project by username: " + application);
132 }
133
134 return getConfigPassword(environment);
135 }
136 }