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,10 +200,10 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt | ||
200 | .addFilterBefore(buildRefreshTokenProcessingFilter(), UsernamePasswordAuthenticationFilter.class) | 200 | .addFilterBefore(buildRefreshTokenProcessingFilter(), UsernamePasswordAuthenticationFilter.class) |
201 | .addFilterBefore(buildWsJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class) | 201 | .addFilterBefore(buildWsJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class) |
202 | .addFilterAfter(rateLimitProcessingFilter, UsernamePasswordAuthenticationFilter.class); | 202 | .addFilterAfter(rateLimitProcessingFilter, UsernamePasswordAuthenticationFilter.class); |
203 | - if (oauth2Configuration.isEnabled()) { | 203 | + if (oauth2Configuration != null && oauth2Configuration.isEnabled()) { |
204 | http.oauth2Login() | 204 | http.oauth2Login() |
205 | .loginPage("/oauth2Login") | 205 | .loginPage("/oauth2Login") |
206 | - .loginProcessingUrl(oauth2Configuration.getClients().values().iterator().next().getLoginProcessingUrl()) | 206 | + .loginProcessingUrl(oauth2Configuration.getLoginProcessingUrl()) |
207 | .successHandler(oauth2AuthenticationSuccessHandler); | 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,9 +36,11 @@ import org.thingsboard.server.service.security.model.UserPrincipal; | ||
36 | 36 | ||
37 | import java.util.List; | 37 | import java.util.List; |
38 | import java.util.Optional; | 38 | import java.util.Optional; |
39 | +import java.util.concurrent.locks.Lock; | ||
40 | +import java.util.concurrent.locks.ReentrantLock; | ||
39 | 41 | ||
40 | @Slf4j | 42 | @Slf4j |
41 | -public abstract class BaseOAuth2ClientMapper { | 43 | +public abstract class AbstractOAuth2ClientMapper { |
42 | 44 | ||
43 | @Autowired | 45 | @Autowired |
44 | private UserService userService; | 46 | private UserService userService; |
@@ -49,6 +51,8 @@ public abstract class BaseOAuth2ClientMapper { | @@ -49,6 +51,8 @@ public abstract class BaseOAuth2ClientMapper { | ||
49 | @Autowired | 51 | @Autowired |
50 | private CustomerService customerService; | 52 | private CustomerService customerService; |
51 | 53 | ||
54 | + private final Lock userCreationLock = new ReentrantLock(); | ||
55 | + | ||
52 | protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, boolean allowUserCreation) { | 56 | protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, boolean allowUserCreation) { |
53 | UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, oauth2User.getEmail()); | 57 | UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, oauth2User.getEmail()); |
54 | 58 | ||
@@ -59,18 +63,30 @@ public abstract class BaseOAuth2ClientMapper { | @@ -59,18 +63,30 @@ public abstract class BaseOAuth2ClientMapper { | ||
59 | } | 63 | } |
60 | 64 | ||
61 | if (user == null) { | 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 | try { | 92 | try { |
@@ -78,7 +94,7 @@ public abstract class BaseOAuth2ClientMapper { | @@ -78,7 +94,7 @@ public abstract class BaseOAuth2ClientMapper { | ||
78 | return (SecurityUser) new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities()).getPrincipal(); | 94 | return (SecurityUser) new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities()).getPrincipal(); |
79 | } catch (Exception e) { | 95 | } catch (Exception e) { |
80 | log.error("Can't get or create security user from oauth2 user", e); | 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,7 +28,13 @@ import java.util.Map; | ||
28 | 28 | ||
29 | @Service(value = "basicOAuth2ClientMapper") | 29 | @Service(value = "basicOAuth2ClientMapper") |
30 | @Slf4j | 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 | @Override | 39 | @Override |
34 | public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig config) { | 40 | public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig config) { |
@@ -46,7 +52,7 @@ public class BasicOAuth2ClientMapper extends BaseOAuth2ClientMapper implements O | @@ -46,7 +52,7 @@ public class BasicOAuth2ClientMapper extends BaseOAuth2ClientMapper implements O | ||
46 | oauth2User.setFirstName(firstName); | 52 | oauth2User.setFirstName(firstName); |
47 | } | 53 | } |
48 | if (!StringUtils.isEmpty(config.getBasic().getCustomerNameStrategyPattern())) { | 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 | String customerName = sub.replace(config.getBasic().getCustomerNameStrategyPattern()); | 56 | String customerName = sub.replace(config.getBasic().getCustomerNameStrategyPattern()); |
51 | oauth2User.setCustomerName(customerName); | 57 | oauth2User.setCustomerName(customerName); |
52 | } | 58 | } |
@@ -55,11 +61,13 @@ public class BasicOAuth2ClientMapper extends BaseOAuth2ClientMapper implements O | @@ -55,11 +61,13 @@ public class BasicOAuth2ClientMapper extends BaseOAuth2ClientMapper implements O | ||
55 | 61 | ||
56 | private String getTenantName(Map<String, Object> attributes, OAuth2ClientMapperConfig config) { | 62 | private String getTenantName(Map<String, Object> attributes, OAuth2ClientMapperConfig config) { |
57 | switch (config.getBasic().getTenantNameStrategy()) { | 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 | String email = getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey()); | 67 | String email = getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey()); |
60 | return email.substring(email .indexOf("@") + 1); | 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 | return sub.replace(config.getBasic().getTenantNameStrategyPattern()); | 71 | return sub.replace(config.getBasic().getTenantNameStrategyPattern()); |
64 | default: | 72 | default: |
65 | throw new RuntimeException("Tenant Name Strategy with type " + config.getBasic().getTenantNameStrategy() + " is not supported!"); | 73 | throw new RuntimeException("Tenant Name Strategy with type " + config.getBasic().getTenantNameStrategy() + " is not supported!"); |
@@ -15,6 +15,8 @@ | @@ -15,6 +15,8 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.service.security.auth.oauth2; | 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 | import lombok.extern.slf4j.Slf4j; | 20 | import lombok.extern.slf4j.Slf4j; |
19 | import org.springframework.boot.web.client.RestTemplateBuilder; | 21 | import org.springframework.boot.web.client.RestTemplateBuilder; |
20 | import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; | 22 | import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; |
@@ -27,7 +29,9 @@ import org.thingsboard.server.service.security.model.SecurityUser; | @@ -27,7 +29,9 @@ import org.thingsboard.server.service.security.model.SecurityUser; | ||
27 | 29 | ||
28 | @Service(value = "customOAuth2ClientMapper") | 30 | @Service(value = "customOAuth2ClientMapper") |
29 | @Slf4j | 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 | private RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); | 36 | private RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); |
33 | 37 | ||
@@ -42,6 +46,18 @@ public class CustomOAuth2ClientMapper extends BaseOAuth2ClientMapper implements | @@ -42,6 +46,18 @@ public class CustomOAuth2ClientMapper extends BaseOAuth2ClientMapper implements | ||
42 | restTemplateBuilder = restTemplateBuilder.basicAuthentication(custom.getUsername(), custom.getPassword()); | 46 | restTemplateBuilder = restTemplateBuilder.basicAuthentication(custom.getUsername(), custom.getPassword()); |
43 | } | 47 | } |
44 | RestTemplate restTemplate = restTemplateBuilder.build(); | 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,72 +98,40 @@ security: | ||
98 | # Time allowed to claim the device in milliseconds | 98 | # Time allowed to claim the device in milliseconds |
99 | duration: "${SECURITY_CLAIM_DURATION:60000}" # 1 minute, note this value must equal claimDevices.timeToLiveInMinutes value | 99 | duration: "${SECURITY_CLAIM_DURATION:60000}" # 1 minute, note this value must equal claimDevices.timeToLiveInMinutes value |
100 | basic: | 100 | basic: |
101 | - enabled: false | 101 | + enabled: "${SECURITY_BASIC_ENABLED:false}" |
102 | oauth2: | 102 | oauth2: |
103 | - enabled: true | 103 | + enabled: "${SECURITY_OAUTH2_ENABLED:false}" |
104 | + loginProcessingUrl: "${SECURITY_OAUTH2_LOGIN_PROCESSING_URL:/login/oauth2/code/}" | ||
104 | clients: | 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 | mapperConfig: | 121 | mapperConfig: |
123 | - type: custom # basic or custom | 122 | + type: "${SECURITY_OAUTH2_DEFAULT_MAPPER_TYPE:basic}" # basic or custom |
124 | basic: | 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 | custom: | 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 | # Dashboard parameters | 136 | # Dashboard parameters |
169 | dashboard: | 137 | dashboard: |
@@ -16,11 +16,15 @@ | @@ -16,11 +16,15 @@ | ||
16 | package org.thingsboard.server.dao.oauth2; | 16 | package org.thingsboard.server.dao.oauth2; |
17 | 17 | ||
18 | import lombok.Data; | 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 | @Data | 22 | @Data |
21 | public class OAuth2User { | 23 | public class OAuth2User { |
22 | private String tenantName; | 24 | private String tenantName; |
25 | + private TenantId tenantId; | ||
23 | private String customerName; | 26 | private String customerName; |
27 | + private CustomerId customerId; | ||
24 | private String email; | 28 | private String email; |
25 | private String firstName; | 29 | private String firstName; |
26 | private String lastName; | 30 | private String lastName; |
@@ -20,7 +20,6 @@ import lombok.Data; | @@ -20,7 +20,6 @@ import lombok.Data; | ||
20 | @Data | 20 | @Data |
21 | public class OAuth2Client { | 21 | public class OAuth2Client { |
22 | 22 | ||
23 | - private String registrationId; | ||
24 | private String loginButtonLabel; | 23 | private String loginButtonLabel; |
25 | private String loginButtonIcon; | 24 | private String loginButtonIcon; |
26 | private String clientName; | 25 | private String clientName; |
@@ -31,7 +30,6 @@ public class OAuth2Client { | @@ -31,7 +30,6 @@ public class OAuth2Client { | ||
31 | private String scope; | 30 | private String scope; |
32 | private String redirectUriTemplate; | 31 | private String redirectUriTemplate; |
33 | private String jwkSetUri; | 32 | private String jwkSetUri; |
34 | - private String loginProcessingUrl; | ||
35 | private String authorizationGrantType; | 33 | private String authorizationGrantType; |
36 | private String clientAuthenticationMethod; | 34 | private String clientAuthenticationMethod; |
37 | private String userInfoUri; | 35 | private String userInfoUri; |
@@ -21,8 +21,8 @@ import lombok.Data; | @@ -21,8 +21,8 @@ import lombok.Data; | ||
21 | public class OAuth2ClientMapperConfig { | 21 | public class OAuth2ClientMapperConfig { |
22 | 22 | ||
23 | private String type; | 23 | private String type; |
24 | - private CustomOAuth2ClientMapperConfig custom; | ||
25 | private BasicOAuth2ClientMapperConfig basic; | 24 | private BasicOAuth2ClientMapperConfig basic; |
25 | + private CustomOAuth2ClientMapperConfig custom; | ||
26 | 26 | ||
27 | @Data | 27 | @Data |
28 | public static class BasicOAuth2ClientMapperConfig { | 28 | public static class BasicOAuth2ClientMapperConfig { |
@@ -40,13 +40,15 @@ import java.util.Map; | @@ -40,13 +40,15 @@ import java.util.Map; | ||
40 | public class OAuth2Configuration { | 40 | public class OAuth2Configuration { |
41 | 41 | ||
42 | private boolean enabled; | 42 | private boolean enabled; |
43 | + private String loginProcessingUrl; | ||
43 | private Map<String, OAuth2Client> clients = new HashMap<>(); | 44 | private Map<String, OAuth2Client> clients = new HashMap<>(); |
44 | 45 | ||
45 | @Bean | 46 | @Bean |
46 | public ClientRegistrationRepository clientRegistrationRepository() { | 47 | public ClientRegistrationRepository clientRegistrationRepository() { |
47 | List<ClientRegistration> result = new ArrayList<>(); | 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 | .clientId(client.getClientId()) | 52 | .clientId(client.getClientId()) |
51 | .authorizationUri(client.getAuthorizationUri()) | 53 | .authorizationUri(client.getAuthorizationUri()) |
52 | .clientSecret(client.getClientSecret()) | 54 | .clientSecret(client.getClientSecret()) |
@@ -68,9 +70,9 @@ public class OAuth2Configuration { | @@ -68,9 +70,9 @@ public class OAuth2Configuration { | ||
68 | public OAuth2Client getClientByRegistrationId(String registrationId) { | 70 | public OAuth2Client getClientByRegistrationId(String registrationId) { |
69 | OAuth2Client result = null; | 71 | OAuth2Client result = null; |
70 | if (clients != null && !clients.isEmpty()) { | 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 | break; | 76 | break; |
75 | } | 77 | } |
76 | } | 78 | } |
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo; | ||
23 | import java.util.ArrayList; | 23 | import java.util.ArrayList; |
24 | import java.util.Collections; | 24 | import java.util.Collections; |
25 | import java.util.List; | 25 | import java.util.List; |
26 | +import java.util.Map; | ||
26 | 27 | ||
27 | @Slf4j | 28 | @Slf4j |
28 | @Service | 29 | @Service |
@@ -33,15 +34,15 @@ public class OAuth2ServiceImpl implements OAuth2Service { | @@ -33,15 +34,15 @@ public class OAuth2ServiceImpl implements OAuth2Service { | ||
33 | 34 | ||
34 | @Override | 35 | @Override |
35 | public List<OAuth2ClientInfo> getOAuth2Clients() { | 36 | public List<OAuth2ClientInfo> getOAuth2Clients() { |
36 | - if (!oauth2Configuration.isEnabled()) { | 37 | + if (oauth2Configuration == null || !oauth2Configuration.isEnabled()) { |
37 | return Collections.emptyList(); | 38 | return Collections.emptyList(); |
38 | } | 39 | } |
39 | List<OAuth2ClientInfo> result = new ArrayList<>(); | 40 | List<OAuth2ClientInfo> result = new ArrayList<>(); |
40 | - for (OAuth2Client c : oauth2Configuration.getClients().values()) { | 41 | + for (Map.Entry<String, OAuth2Client> entry : oauth2Configuration.getClients().entrySet()) { |
41 | OAuth2ClientInfo client = new OAuth2ClientInfo(); | 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 | result.add(client); | 46 | result.add(client); |
46 | } | 47 | } |
47 | return result; | 48 | return result; |