Commit 78d054797e9c702bac558501ae9461e31cd31d18

Authored by Igor Kulikov
Committed by GitHub
2 parents 676868b4 4ed334a5

Merge pull request #2806 from vzikratyi-tb/oauth2-default-dashboard

Oauth2 default dashboard
... ... @@ -15,6 +15,9 @@
15 15 */
16 16 package org.thingsboard.server.service.security.auth.oauth2;
17 17
  18 +import com.fasterxml.jackson.databind.ObjectMapper;
  19 +import com.fasterxml.jackson.databind.node.ObjectNode;
  20 +import com.google.common.base.Strings;
18 21 import lombok.extern.slf4j.Slf4j;
19 22 import org.springframework.beans.factory.annotation.Autowired;
20 23 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
... ... @@ -22,14 +25,21 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
22 25 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
23 26 import org.springframework.util.StringUtils;
24 27 import org.thingsboard.server.common.data.Customer;
  28 +import org.thingsboard.server.common.data.DashboardInfo;
25 29 import org.thingsboard.server.common.data.Tenant;
26 30 import org.thingsboard.server.common.data.User;
27 31 import org.thingsboard.server.common.data.id.CustomerId;
  32 +import org.thingsboard.server.common.data.id.DashboardId;
  33 +import org.thingsboard.server.common.data.id.IdBased;
28 34 import org.thingsboard.server.common.data.id.TenantId;
  35 +import org.thingsboard.server.common.data.page.TextPageData;
29 36 import org.thingsboard.server.common.data.page.TextPageLink;
  37 +import org.thingsboard.server.common.data.page.TimePageData;
  38 +import org.thingsboard.server.common.data.page.TimePageLink;
30 39 import org.thingsboard.server.common.data.security.Authority;
31 40 import org.thingsboard.server.common.data.security.UserCredentials;
32 41 import org.thingsboard.server.dao.customer.CustomerService;
  42 +import org.thingsboard.server.dao.dashboard.DashboardService;
33 43 import org.thingsboard.server.dao.oauth2.OAuth2User;
34 44 import org.thingsboard.server.dao.tenant.TenantService;
35 45 import org.thingsboard.server.dao.user.UserService;
... ... @@ -40,11 +50,15 @@ import org.thingsboard.server.service.security.model.UserPrincipal;
40 50 import java.io.IOException;
41 51 import java.util.List;
42 52 import java.util.Optional;
  53 +import java.util.concurrent.ExecutionException;
43 54 import java.util.concurrent.locks.Lock;
44 55 import java.util.concurrent.locks.ReentrantLock;
45 56
46 57 @Slf4j
47 58 public abstract class AbstractOAuth2ClientMapper {
  59 + private static final int DASHBOARDS_REQUEST_LIMIT = 10;
  60 +
  61 + private static final ObjectMapper objectMapper = new ObjectMapper();
48 62
49 63 @Autowired
50 64 private UserService userService;
... ... @@ -59,6 +73,9 @@ public abstract class AbstractOAuth2ClientMapper {
59 73 private CustomerService customerService;
60 74
61 75 @Autowired
  76 + private DashboardService dashboardService;
  77 +
  78 + @Autowired
62 79 private InstallScripts installScripts;
63 80
64 81 private final Lock userCreationLock = new ReentrantLock();
... ... @@ -92,6 +109,20 @@ public abstract class AbstractOAuth2ClientMapper {
92 109 user.setEmail(oauth2User.getEmail());
93 110 user.setFirstName(oauth2User.getFirstName());
94 111 user.setLastName(oauth2User.getLastName());
  112 +
  113 + if (!StringUtils.isEmpty(oauth2User.getDefaultDashboardName())) {
  114 + Optional<DashboardId> dashboardIdOpt =
  115 + user.getAuthority() == Authority.TENANT_ADMIN ?
  116 + getDashboardId(tenantId, oauth2User.getDefaultDashboardName())
  117 + : getDashboardId(tenantId, customerId, oauth2User.getDefaultDashboardName());
  118 + if (dashboardIdOpt.isPresent()) {
  119 + ObjectNode additionalInfo = objectMapper.createObjectNode();
  120 + additionalInfo.put("defaultDashboardFullscreen", oauth2User.isAlwaysFullScreen());
  121 + additionalInfo.put("defaultDashboardId", dashboardIdOpt.get().getId().toString());
  122 + user.setAdditionalInfo(additionalInfo);
  123 + }
  124 + }
  125 +
95 126 user = userService.saveUser(user);
96 127 if (activateUser) {
97 128 UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
... ... @@ -143,4 +174,32 @@ public abstract class AbstractOAuth2ClientMapper {
143 174 return customerService.saveCustomer(customer).getId();
144 175 }
145 176 }
  177 +
  178 + private Optional<DashboardId> getDashboardId(TenantId tenantId, String dashboardName) {
  179 + TextPageLink searchTextLink = new TextPageLink(1, dashboardName);
  180 + TextPageData<DashboardInfo> dashboardsPage = dashboardService.findDashboardsByTenantId(tenantId, searchTextLink);
  181 + return dashboardsPage.getData().stream()
  182 + .findAny()
  183 + .map(IdBased::getId);
  184 + }
  185 +
  186 + private Optional<DashboardId> getDashboardId(TenantId tenantId, CustomerId customerId, String dashboardName) {
  187 + TimePageData<DashboardInfo> dashboardsPage = null;
  188 + do {
  189 + TimePageLink timePageLink = dashboardsPage != null ?
  190 + dashboardsPage.getNextPageLink() : new TimePageLink(DASHBOARDS_REQUEST_LIMIT);
  191 + try {
  192 + dashboardsPage = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, timePageLink).get();
  193 + } catch (InterruptedException | ExecutionException e) {
  194 + throw new RuntimeException("Failed to get customer's dashboards.", e);
  195 + }
  196 + Optional<DashboardInfo> dashboardInfoOpt = dashboardsPage.getData().stream()
  197 + .filter(dashboardInfo -> dashboardName.equals(dashboardInfo.getName()))
  198 + .findAny();
  199 + if (dashboardInfoOpt.isPresent()) {
  200 + return dashboardInfoOpt.map(DashboardInfo::getId);
  201 + }
  202 + } while (dashboardsPage.hasNext());
  203 + return Optional.empty();
  204 + }
146 205 }
... ...
... ... @@ -56,6 +56,10 @@ public class BasicOAuth2ClientMapper extends AbstractOAuth2ClientMapper implemen
56 56 String customerName = sub.replace(config.getBasic().getCustomerNamePattern());
57 57 oauth2User.setCustomerName(customerName);
58 58 }
  59 + oauth2User.setAlwaysFullScreen(config.getBasic().isAlwaysFullScreen());
  60 + if (!StringUtils.isEmpty(config.getBasic().getDefaultDashboardName())) {
  61 + oauth2User.setDefaultDashboardName(config.getBasic().getDefaultDashboardName());
  62 + }
59 63
60 64 return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.isAllowUserCreation(), config.isActivateUser());
61 65 }
... ...
... ... @@ -148,6 +148,10 @@ security:
148 148 # If this field is not empty, user will be created as a user under defined Customer
149 149 # %{attribute_key} as placeholder for attribute value of attributes of external user object
150 150 customerNamePattern: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_CUSTOMER_NAME_PATTERN:}"
  151 + # If this field is not empty, user will be created with default defined Dashboard
  152 + defaultDashboardName: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_DEFAULT_DASHBOARD_NAME:}"
  153 + # If this field is set 'true' along with non-empty 'defaultDashboardName', user will start from the defined Dashboard in fullscreen mode
  154 + alwaysFullScreen: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_ALWAYS_FULL_SCREEN:false}"
151 155 custom:
152 156 url: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_URL:}"
153 157 username: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_USERNAME:}"
... ...
... ... @@ -28,4 +28,6 @@ public class OAuth2User {
28 28 private String email;
29 29 private String firstName;
30 30 private String lastName;
  31 + private boolean alwaysFullScreen;
  32 + private String defaultDashboardName;
31 33 }
... ...
... ... @@ -34,6 +34,8 @@ public class OAuth2ClientMapperConfig {
34 34 private String tenantNameStrategy;
35 35 private String tenantNamePattern;
36 36 private String customerNamePattern;
  37 + private boolean alwaysFullScreen;
  38 + private String defaultDashboardName;
37 39 }
38 40
39 41 @Data
... ...