Commit 8dbc550fd3bb0f0609ffdd8fbfe9e9edd3eb082f
Committed by
Andrew Shvayka
1 parent
d644dddc
Refactoring to review. Added tenantId and customerId. Added email tenant name strategy
Showing
10 changed files
with
109 additions
and
96 deletions
... | ... | @@ -200,10 +200,10 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
200 | 200 | .addFilterBefore(buildRefreshTokenProcessingFilter(), UsernamePasswordAuthenticationFilter.class) |
201 | 201 | .addFilterBefore(buildWsJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class) |
202 | 202 | .addFilterAfter(rateLimitProcessingFilter, UsernamePasswordAuthenticationFilter.class); |
203 | - if (oauth2Configuration.isEnabled()) { | |
203 | + if (oauth2Configuration != null && oauth2Configuration.isEnabled()) { | |
204 | 204 | http.oauth2Login() |
205 | 205 | .loginPage("/oauth2Login") |
206 | - .loginProcessingUrl(oauth2Configuration.getClients().values().iterator().next().getLoginProcessingUrl()) | |
206 | + .loginProcessingUrl(oauth2Configuration.getLoginProcessingUrl()) | |
207 | 207 | .successHandler(oauth2AuthenticationSuccessHandler); |
208 | 208 | } |
209 | 209 | } | ... | ... |
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java
renamed from
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/BaseOAuth2ClientMapper.java
... | ... | @@ -36,9 +36,11 @@ import org.thingsboard.server.service.security.model.UserPrincipal; |
36 | 36 | |
37 | 37 | import java.util.List; |
38 | 38 | import java.util.Optional; |
39 | +import java.util.concurrent.locks.Lock; | |
40 | +import java.util.concurrent.locks.ReentrantLock; | |
39 | 41 | |
40 | 42 | @Slf4j |
41 | -public abstract class BaseOAuth2ClientMapper { | |
43 | +public abstract class AbstractOAuth2ClientMapper { | |
42 | 44 | |
43 | 45 | @Autowired |
44 | 46 | private UserService userService; |
... | ... | @@ -49,6 +51,8 @@ public abstract class BaseOAuth2ClientMapper { |
49 | 51 | @Autowired |
50 | 52 | private CustomerService customerService; |
51 | 53 | |
54 | + private final Lock userCreationLock = new ReentrantLock(); | |
55 | + | |
52 | 56 | protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, boolean allowUserCreation) { |
53 | 57 | UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, oauth2User.getEmail()); |
54 | 58 | |
... | ... | @@ -59,18 +63,30 @@ public abstract class BaseOAuth2ClientMapper { |
59 | 63 | } |
60 | 64 | |
61 | 65 | if (user == null) { |
62 | - user = new User(); | |
63 | - if (StringUtils.isEmpty(oauth2User.getCustomerName())) { | |
64 | - user.setAuthority(Authority.TENANT_ADMIN); | |
65 | - } else { | |
66 | - user.setAuthority(Authority.CUSTOMER_USER); | |
66 | + userCreationLock.lock(); | |
67 | + try { | |
68 | + user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, oauth2User.getEmail()); | |
69 | + if (user == null) { | |
70 | + user = new User(); | |
71 | + if (oauth2User.getCustomerId() == null && StringUtils.isEmpty(oauth2User.getCustomerName())) { | |
72 | + user.setAuthority(Authority.TENANT_ADMIN); | |
73 | + } else { | |
74 | + user.setAuthority(Authority.CUSTOMER_USER); | |
75 | + } | |
76 | + TenantId tenantId = oauth2User.getTenantId() != null ? | |
77 | + oauth2User.getTenantId() : getTenantId(oauth2User.getTenantName()); | |
78 | + user.setTenantId(tenantId); | |
79 | + CustomerId customerId = oauth2User.getCustomerId() != null ? | |
80 | + oauth2User.getCustomerId() : getCustomerId(user.getTenantId(), oauth2User.getCustomerName()); | |
81 | + user.setCustomerId(customerId); | |
82 | + user.setEmail(oauth2User.getEmail()); | |
83 | + user.setFirstName(oauth2User.getFirstName()); | |
84 | + user.setLastName(oauth2User.getLastName()); | |
85 | + user = userService.saveUser(user); | |
86 | + } | |
87 | + } finally { | |
88 | + userCreationLock.unlock(); | |
67 | 89 | } |
68 | - user.setTenantId(getTenantId(oauth2User.getTenantName())); | |
69 | - user.setCustomerId(getCustomerId(user.getTenantId(), oauth2User.getCustomerName())); | |
70 | - user.setEmail(oauth2User.getEmail()); | |
71 | - user.setFirstName(oauth2User.getFirstName()); | |
72 | - user.setLastName(oauth2User.getLastName()); | |
73 | - user = userService.saveUser(user); | |
74 | 90 | } |
75 | 91 | |
76 | 92 | try { |
... | ... | @@ -78,7 +94,7 @@ public abstract class BaseOAuth2ClientMapper { |
78 | 94 | return (SecurityUser) new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities()).getPrincipal(); |
79 | 95 | } catch (Exception e) { |
80 | 96 | log.error("Can't get or create security user from oauth2 user", e); |
81 | - throw e; | |
97 | + throw new RuntimeException("Can't get or create security user from oauth2 user", e); | |
82 | 98 | } |
83 | 99 | } |
84 | 100 | ... | ... |
... | ... | @@ -28,7 +28,13 @@ import java.util.Map; |
28 | 28 | |
29 | 29 | @Service(value = "basicOAuth2ClientMapper") |
30 | 30 | @Slf4j |
31 | -public class BasicOAuth2ClientMapper extends BaseOAuth2ClientMapper implements OAuth2ClientMapper { | |
31 | +public class BasicOAuth2ClientMapper extends AbstractOAuth2ClientMapper implements OAuth2ClientMapper { | |
32 | + | |
33 | + private static final String START_PLACEHOLDER_PREFIX = "%{"; | |
34 | + private static final String END_PLACEHOLDER_PREFIX = "}"; | |
35 | + private static final String EMAIL_TENANT_STRATEGY = "email"; | |
36 | + private static final String DOMAIN_TENANT_STRATEGY = "domain"; | |
37 | + private static final String CUSTOM_TENANT_STRATEGY = "custom"; | |
32 | 38 | |
33 | 39 | @Override |
34 | 40 | public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig config) { |
... | ... | @@ -46,7 +52,7 @@ public class BasicOAuth2ClientMapper extends BaseOAuth2ClientMapper implements O |
46 | 52 | oauth2User.setFirstName(firstName); |
47 | 53 | } |
48 | 54 | if (!StringUtils.isEmpty(config.getBasic().getCustomerNameStrategyPattern())) { |
49 | - StrSubstitutor sub = new StrSubstitutor(attributes, "${", "}"); | |
55 | + StrSubstitutor sub = new StrSubstitutor(attributes, START_PLACEHOLDER_PREFIX, END_PLACEHOLDER_PREFIX); | |
50 | 56 | String customerName = sub.replace(config.getBasic().getCustomerNameStrategyPattern()); |
51 | 57 | oauth2User.setCustomerName(customerName); |
52 | 58 | } |
... | ... | @@ -55,11 +61,13 @@ public class BasicOAuth2ClientMapper extends BaseOAuth2ClientMapper implements O |
55 | 61 | |
56 | 62 | private String getTenantName(Map<String, Object> attributes, OAuth2ClientMapperConfig config) { |
57 | 63 | switch (config.getBasic().getTenantNameStrategy()) { |
58 | - case "domain": | |
64 | + case EMAIL_TENANT_STRATEGY: | |
65 | + return getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey()); | |
66 | + case DOMAIN_TENANT_STRATEGY: | |
59 | 67 | String email = getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey()); |
60 | 68 | return email.substring(email .indexOf("@") + 1); |
61 | - case "custom": | |
62 | - StrSubstitutor sub = new StrSubstitutor(attributes, "${", "}"); | |
69 | + case CUSTOM_TENANT_STRATEGY: | |
70 | + StrSubstitutor sub = new StrSubstitutor(attributes, START_PLACEHOLDER_PREFIX, END_PLACEHOLDER_PREFIX); | |
63 | 71 | return sub.replace(config.getBasic().getTenantNameStrategyPattern()); |
64 | 72 | default: |
65 | 73 | throw new RuntimeException("Tenant Name Strategy with type " + config.getBasic().getTenantNameStrategy() + " is not supported!"); | ... | ... |
... | ... | @@ -15,6 +15,8 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.security.auth.oauth2; |
17 | 17 | |
18 | +import com.fasterxml.jackson.core.JsonProcessingException; | |
19 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
18 | 20 | import lombok.extern.slf4j.Slf4j; |
19 | 21 | import org.springframework.boot.web.client.RestTemplateBuilder; |
20 | 22 | import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; |
... | ... | @@ -27,7 +29,9 @@ import org.thingsboard.server.service.security.model.SecurityUser; |
27 | 29 | |
28 | 30 | @Service(value = "customOAuth2ClientMapper") |
29 | 31 | @Slf4j |
30 | -public class CustomOAuth2ClientMapper extends BaseOAuth2ClientMapper implements OAuth2ClientMapper { | |
32 | +public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper implements OAuth2ClientMapper { | |
33 | + | |
34 | + private static final ObjectMapper json = new ObjectMapper(); | |
31 | 35 | |
32 | 36 | private RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); |
33 | 37 | |
... | ... | @@ -42,6 +46,18 @@ public class CustomOAuth2ClientMapper extends BaseOAuth2ClientMapper implements |
42 | 46 | restTemplateBuilder = restTemplateBuilder.basicAuthentication(custom.getUsername(), custom.getPassword()); |
43 | 47 | } |
44 | 48 | RestTemplate restTemplate = restTemplateBuilder.build(); |
45 | - return restTemplate.postForEntity(custom.getUrl(), token.getPrincipal(), OAuth2User.class).getBody(); | |
49 | + String request; | |
50 | + try { | |
51 | + request = json.writeValueAsString(token.getPrincipal()); | |
52 | + } catch (JsonProcessingException e) { | |
53 | + log.error("Can't convert principal to JSON string", e); | |
54 | + throw new RuntimeException("Can't convert principal to JSON string", e); | |
55 | + } | |
56 | + try { | |
57 | + return restTemplate.postForEntity(custom.getUrl(), request, OAuth2User.class).getBody(); | |
58 | + } catch (Exception e) { | |
59 | + log.error("Can't connect to custom mapper endpoint", e); | |
60 | + throw new RuntimeException("Can't connect to custom mapper endpoint", e); | |
61 | + } | |
46 | 62 | } |
47 | 63 | } | ... | ... |
... | ... | @@ -98,72 +98,40 @@ security: |
98 | 98 | # Time allowed to claim the device in milliseconds |
99 | 99 | duration: "${SECURITY_CLAIM_DURATION:60000}" # 1 minute, note this value must equal claimDevices.timeToLiveInMinutes value |
100 | 100 | basic: |
101 | - enabled: false | |
101 | + enabled: "${SECURITY_BASIC_ENABLED:false}" | |
102 | 102 | oauth2: |
103 | - enabled: true | |
103 | + enabled: "${SECURITY_OAUTH2_ENABLED:false}" | |
104 | + loginProcessingUrl: "${SECURITY_OAUTH2_LOGIN_PROCESSING_URL:/login/oauth2/code/}" | |
104 | 105 | clients: |
105 | - schwarz: | |
106 | - registrationId: A | |
107 | - loginButtonLabel: Auth0 # | |
108 | - loginButtonIcon: | |
109 | - clientName: Test app | |
110 | - clientId: dVH9reqyqiXIG7M2wmamb0ySue8zaM4g | |
111 | - clientSecret: EYAfAGxwkwoeYnb2o2cDgaWZB5k97OStpZQPPvcMMD-SVH2BuughTGeBazXtF5I6 | |
112 | - accessTokenUri: https://dev-r9m8ht0k.auth0.com/oauth/token | |
113 | - authorizationUri: https://dev-r9m8ht0k.auth0.com/authorize | |
114 | - scope: openid,profile,email | |
115 | - redirectUriTemplate: http://localhost:8080/login/oauth2/code/ | |
116 | - loginProcessingUrl: /login/oauth2/code/ | |
117 | - jwkSetUri: https://dev-r9m8ht0k.auth0.com/.well-known/jwks.json | |
118 | - authorizationGrantType: authorization_code # authorization_code, implicit, refresh_token, client_credentials | |
119 | - clientAuthenticationMethod: post # basic, post | |
120 | - userInfoUri: https://dev-r9m8ht0k.auth0.com/userinfo | |
121 | - userNameAttributeName: email | |
106 | + default: | |
107 | + loginButtonLabel: "${SECURITY_OAUTH2_DEFAULT_LOGIN_BUTTON_LABEL:Default}" # Label that going to be show on login screen | |
108 | + loginButtonIcon: "${SECURITY_OAUTH2_DEFAULT_LOGIN_BUTTON_ICON:}" # Icon that going to be show on login screen. Material design icon ID (https://material.angularjs.org/latest/api/directive/mdIcon) | |
109 | + clientName: "${SECURITY_OAUTH2_DEFAULT_CLIENT_NAME:ClientName}" | |
110 | + clientId: "${SECURITY_OAUTH2_DEFAULT_CLIENT_ID:}" | |
111 | + clientSecret: "${SECURITY_OAUTH2_DEFAULT_CLIENT_SECRET:}" | |
112 | + accessTokenUri: "${SECURITY_OAUTH2_DEFAULT_ACCESS_TOKEN_URI:}" | |
113 | + authorizationUri: "${SECURITY_OAUTH2_DEFAULT_AUTHORIZATION_URI:}" | |
114 | + scope: "${SECURITY_OAUTH2_DEFAULT_SCOPE:}" | |
115 | + redirectUriTemplate: "${SECURITY_OAUTH2_DEFAULT_REDIRECT_URI_TEMPLATE:http://localhost:8080/login/oauth2/code/}" # Must be in sync with security.oauth2.loginProcessingUrl | |
116 | + jwkSetUri: "${SECURITY_OAUTH2_DEFAULT_JWK_SET_URI:}" | |
117 | + authorizationGrantType: "${SECURITY_OAUTH2_DEFAULT_AUTHORIZATION_GRANT_TYPE:authorization_code}" # authorization_code, implicit, refresh_token or client_credentials | |
118 | + clientAuthenticationMethod: "${SECURITY_OAUTH2_DEFAULT_CLIENT_AUTHENTICATION_METHOD:post}" # basic or post | |
119 | + userInfoUri: "${SECURITY_OAUTH2_DEFAULT_USER_INFO_URI:}" | |
120 | + userNameAttributeName: "${SECURITY_OAUTH2_DEFAULT_USER_NAME_ATTRIBUTE_NAME:email}" | |
122 | 121 | mapperConfig: |
123 | - type: custom # basic or custom | |
122 | + type: "${SECURITY_OAUTH2_DEFAULT_MAPPER_TYPE:basic}" # basic or custom | |
124 | 123 | basic: |
125 | - allowUserCreation: true # required | |
126 | - emailAttributeKey: email # required | |
127 | - firstNameAttributeKey: | |
128 | - lastNameAttributeKey: | |
129 | - tenantNameStrategy: domain # domain or custom | |
130 | - tenantNameStrategyPattern: | |
131 | - customerNameStrategyPattern: | |
124 | + allowUserCreation: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_ALLOW_USER_CREATION:true}" # Allows to create user if it not exists | |
125 | + emailAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_EMAIL_ATTRIBUTE_KEY:email}" # Attribute key to use as email for the user | |
126 | + firstNameAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_FIRST_NAME_ATTRIBUTE_KEY:}" | |
127 | + lastNameAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_LAST_NAME_ATTRIBUTE_KEY:}" | |
128 | + tenantNameStrategy: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_TENANT_NAME_STRATEGY:domain}" # domain, email or custom | |
129 | + tenantNameStrategyPattern: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_TENANT_NAME_STRATEGY_PATTERN:}" | |
130 | + customerNameStrategyPattern: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_CUSTOMER_NAME_STRATEGY_PATTERN:}" | |
132 | 131 | custom: |
133 | - url: http://localhost:9090/oauth2/mapper | |
134 | - username: admin | |
135 | - password: bababa | |
136 | - auth0: | |
137 | - registrationId: B | |
138 | - loginButtonLabel: Schwarz # | |
139 | - loginButtonIcon: mdi:google | |
140 | - clientName: Thingsboard Dev Test Q | |
141 | - clientId: 5f5c0998-1d9b-4679-9610-6108fb91af2a | |
142 | - clientSecret: h_kXVb7Ee1LgDDinix_nkAh_owWX7YCO783NNteF9AIOqlTWu2L03YoFjv5KL8yRVyx4uYAE-r_N3tFbupE8Kw | |
143 | - accessTokenUri: https://federation-q.auth.schwarz/nidp/oauth/nam/token | |
144 | - authorizationUri: https://federation-q.auth.schwarz/nidp/oauth/nam/authz | |
145 | - scope: openid,profile,email,siam | |
146 | - redirectUriTemplate: http://localhost:8080/login/oauth2/code/ | |
147 | - loginProcessingUrl: /login/oauth2/code/ | |
148 | - jwkSetUri: https://federation-q.auth.schwarz/nidp/oauth/nam/keys | |
149 | - authorizationGrantType: authorization_code # authorization_code, implicit, refresh_token, client_credentials | |
150 | - clientAuthenticationMethod: post # basic, post | |
151 | - userInfoUri: https://federation-q.auth.schwarz/nidp/oauth/nam/userinfo | |
152 | - userNameAttributeName: mail | |
153 | - mapperConfig: | |
154 | - type: basic # simple or custom | |
155 | - basic: | |
156 | - allowUserCreation: true # required | |
157 | - emailAttributeKey: CloudLoginName # required | |
158 | - firstNameAttributeKey: givenName | |
159 | - lastNameAttributeKey: sn | |
160 | - tenantNameStrategy: custom # domain or custom | |
161 | - tenantNameStrategyPattern: LOL ${region} | |
162 | - customerNameStrategyPattern: GGG ${countrycode} | |
163 | - custom: | |
164 | - url: http://localhost:9090/oauth2/mapper | |
165 | - username: test | |
166 | - password: test | |
132 | + url: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_URL:}" | |
133 | + username: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_USERNAME:}" | |
134 | + password: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_PASSWORD:}" | |
167 | 135 | |
168 | 136 | # Dashboard parameters |
169 | 137 | dashboard: | ... | ... |
... | ... | @@ -16,11 +16,15 @@ |
16 | 16 | package org.thingsboard.server.dao.oauth2; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | +import org.thingsboard.server.common.data.id.CustomerId; | |
20 | +import org.thingsboard.server.common.data.id.TenantId; | |
19 | 21 | |
20 | 22 | @Data |
21 | 23 | public class OAuth2User { |
22 | 24 | private String tenantName; |
25 | + private TenantId tenantId; | |
23 | 26 | private String customerName; |
27 | + private CustomerId customerId; | |
24 | 28 | private String email; |
25 | 29 | private String firstName; |
26 | 30 | private String lastName; | ... | ... |
... | ... | @@ -20,7 +20,6 @@ import lombok.Data; |
20 | 20 | @Data |
21 | 21 | public class OAuth2Client { |
22 | 22 | |
23 | - private String registrationId; | |
24 | 23 | private String loginButtonLabel; |
25 | 24 | private String loginButtonIcon; |
26 | 25 | private String clientName; |
... | ... | @@ -31,7 +30,6 @@ public class OAuth2Client { |
31 | 30 | private String scope; |
32 | 31 | private String redirectUriTemplate; |
33 | 32 | private String jwkSetUri; |
34 | - private String loginProcessingUrl; | |
35 | 33 | private String authorizationGrantType; |
36 | 34 | private String clientAuthenticationMethod; |
37 | 35 | private String userInfoUri; | ... | ... |
... | ... | @@ -21,8 +21,8 @@ import lombok.Data; |
21 | 21 | public class OAuth2ClientMapperConfig { |
22 | 22 | |
23 | 23 | private String type; |
24 | - private CustomOAuth2ClientMapperConfig custom; | |
25 | 24 | private BasicOAuth2ClientMapperConfig basic; |
25 | + private CustomOAuth2ClientMapperConfig custom; | |
26 | 26 | |
27 | 27 | @Data |
28 | 28 | public static class BasicOAuth2ClientMapperConfig { | ... | ... |
... | ... | @@ -40,13 +40,15 @@ import java.util.Map; |
40 | 40 | public class OAuth2Configuration { |
41 | 41 | |
42 | 42 | private boolean enabled; |
43 | + private String loginProcessingUrl; | |
43 | 44 | private Map<String, OAuth2Client> clients = new HashMap<>(); |
44 | 45 | |
45 | 46 | @Bean |
46 | 47 | public ClientRegistrationRepository clientRegistrationRepository() { |
47 | 48 | List<ClientRegistration> result = new ArrayList<>(); |
48 | - for (OAuth2Client client : clients.values()) { | |
49 | - ClientRegistration registration = ClientRegistration.withRegistrationId(client.getRegistrationId()) | |
49 | + for (Map.Entry<String, OAuth2Client> entry : clients.entrySet()) { | |
50 | + OAuth2Client client = entry.getValue(); | |
51 | + ClientRegistration registration = ClientRegistration.withRegistrationId(entry.getKey()) | |
50 | 52 | .clientId(client.getClientId()) |
51 | 53 | .authorizationUri(client.getAuthorizationUri()) |
52 | 54 | .clientSecret(client.getClientSecret()) |
... | ... | @@ -68,9 +70,9 @@ public class OAuth2Configuration { |
68 | 70 | public OAuth2Client getClientByRegistrationId(String registrationId) { |
69 | 71 | OAuth2Client result = null; |
70 | 72 | if (clients != null && !clients.isEmpty()) { |
71 | - for (OAuth2Client client : clients.values()) { | |
72 | - if (client.getRegistrationId().equals(registrationId)) { | |
73 | - result = client; | |
73 | + for (String key : clients.keySet()) { | |
74 | + if (key.equals(registrationId)) { | |
75 | + result = clients.get(key); | |
74 | 76 | break; |
75 | 77 | } |
76 | 78 | } | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo; |
23 | 23 | import java.util.ArrayList; |
24 | 24 | import java.util.Collections; |
25 | 25 | import java.util.List; |
26 | +import java.util.Map; | |
26 | 27 | |
27 | 28 | @Slf4j |
28 | 29 | @Service |
... | ... | @@ -33,15 +34,15 @@ public class OAuth2ServiceImpl implements OAuth2Service { |
33 | 34 | |
34 | 35 | @Override |
35 | 36 | public List<OAuth2ClientInfo> getOAuth2Clients() { |
36 | - if (!oauth2Configuration.isEnabled()) { | |
37 | + if (oauth2Configuration == null || !oauth2Configuration.isEnabled()) { | |
37 | 38 | return Collections.emptyList(); |
38 | 39 | } |
39 | 40 | List<OAuth2ClientInfo> result = new ArrayList<>(); |
40 | - for (OAuth2Client c : oauth2Configuration.getClients().values()) { | |
41 | + for (Map.Entry<String, OAuth2Client> entry : oauth2Configuration.getClients().entrySet()) { | |
41 | 42 | OAuth2ClientInfo client = new OAuth2ClientInfo(); |
42 | - client.setName(c.getLoginButtonLabel()); | |
43 | - client.setUrl(String.format("/oauth2/authorization/%s", c.getRegistrationId())); | |
44 | - client.setIcon(c.getLoginButtonIcon()); | |
43 | + client.setName(entry.getValue().getLoginButtonLabel()); | |
44 | + client.setUrl(String.format("/oauth2/authorization/%s", entry.getKey())); | |
45 | + client.setIcon(entry.getValue().getLoginButtonIcon()); | |
45 | 46 | result.add(client); |
46 | 47 | } |
47 | 48 | return result; | ... | ... |