Browse Source

Merged with master

pull/4738/head
Andrii Shvaika 5 years ago
parent
commit
d2998b4389
  1. 6
      application/src/main/data/json/system/widget_bundles/control_widgets.json
  2. 62
      application/src/main/data/upgrade/3.2.2/schema_update.sql
  3. 44
      application/src/main/java/org/thingsboard/server/config/CustomOAuth2AuthorizationRequestResolver.java
  4. 10
      application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java
  5. 27
      application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java
  6. 1
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  7. 26
      application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
  8. 37
      application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java
  9. 12
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java
  10. 8
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/BasicOAuth2ClientMapper.java
  11. 8
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CustomOAuth2ClientMapper.java
  12. 8
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/GithubOAuth2ClientMapper.java
  13. 5
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/OAuth2ClientMapper.java
  14. 16
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java
  15. 27
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java
  16. 22
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/TbOAuth2ParameterNames.java
  17. 69
      application/src/main/java/org/thingsboard/server/service/security/model/token/OAuth2AppTokenFactory.java
  18. 21
      common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java
  19. 33
      common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2DomainId.java
  20. 33
      common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2MobileId.java
  21. 33
      common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ParamsId.java
  22. 33
      common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2RegistrationId.java
  23. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/deprecated/OAuth2ClientRegistrationId.java
  24. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/deprecated/OAuth2ClientRegistrationInfoId.java
  25. 2
      common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java
  26. 2
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java
  27. 42
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Domain.java
  28. 34
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2DomainInfo.java
  29. 31
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java
  30. 42
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Mobile.java
  31. 34
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MobileInfo.java
  32. 40
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Params.java
  33. 39
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ParamsInfo.java
  34. 79
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Registration.java
  35. 4
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2RegistrationInfo.java
  36. 20
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/PlatformType.java
  37. 45
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/ClientRegistrationDto.java
  38. 4
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/DomainInfo.java
  39. 5
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/ExtendedOAuth2ClientRegistrationInfo.java
  40. 8
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientRegistration.java
  41. 6
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientRegistrationInfo.java
  42. 4
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientsDomainParams.java
  43. 4
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientsParams.java
  44. 19
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
  45. 38
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java
  46. 16
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  47. 7
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java
  48. 19
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java
  49. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/LwM2mClientRpcRequest.java
  50. 24
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java
  51. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java
  52. 16
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  53. 76
      dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2DomainEntity.java
  54. 72
      dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2MobileEntity.java
  55. 65
      dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ParamsEntity.java
  56. 221
      dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2RegistrationEntity.java
  57. 7
      dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/AbstractOAuth2ClientRegistrationInfoEntity.java
  58. 5
      dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/ExtendedOAuth2ClientRegistrationInfoEntity.java
  59. 9
      dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/OAuth2ClientRegistrationEntity.java
  60. 5
      dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/OAuth2ClientRegistrationInfoEntity.java
  61. 32
      dao/src/main/java/org/thingsboard/server/dao/oauth2/HybridClientRegistrationRepository.java
  62. 28
      dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2DomainDao.java
  63. 28
      dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2MobileDao.java
  64. 23
      dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ParamsDao.java
  65. 34
      dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2RegistrationDao.java
  66. 252
      dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java
  67. 147
      dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java
  68. 5
      dao/src/main/java/org/thingsboard/server/dao/oauth2/deprecated/OAuth2ClientRegistrationDao.java
  69. 8
      dao/src/main/java/org/thingsboard/server/dao/oauth2/deprecated/OAuth2ClientRegistrationInfoDao.java
  70. 52
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2DomainDao.java
  71. 52
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2MobileDao.java
  72. 47
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ParamsDao.java
  73. 64
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2RegistrationDao.java
  74. 29
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2DomainRepository.java
  75. 28
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2MobileRepository.java
  76. 24
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ParamsRepository.java
  77. 53
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2RegistrationRepository.java
  78. 10
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/JpaOAuth2ClientRegistrationDao.java
  79. 11
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/JpaOAuth2ClientRegistrationInfoDao.java
  80. 9
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/OAuth2ClientRegistrationInfoRepository.java
  81. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/OAuth2ClientRegistrationRepository.java
  82. 76
      dao/src/main/resources/sql/schema-entities-hsql.sql
  83. 76
      dao/src/main/resources/sql/schema-entities.sql
  84. 551
      dao/src/test/java/org/thingsboard/server/dao/service/BaseOAuth2ServiceTest.java
  85. 6
      dao/src/test/resources/sql/hsql/drop-all-tables.sql
  86. 6
      dao/src/test/resources/sql/psql/drop-all-tables.sql
  87. 24
      rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java
  88. 7
      ui-ngx/src/app/core/auth/auth.service.ts
  89. 24
      ui-ngx/src/app/core/http/device-profile.service.ts
  90. 10
      ui-ngx/src/app/core/http/oauth2.service.ts
  91. 11
      ui-ngx/src/app/core/utils.ts
  92. 71
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html
  93. 244
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts
  94. 285
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html
  95. 27
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.scss
  96. 74
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts
  97. 45
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts
  98. 2
      ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts
  99. 34
      ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html
  100. 18
      ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts

6
application/src/main/data/json/system/widget_bundles/control_widgets.json

File diff suppressed because one or more lines are too long

62
application/src/main/data/upgrade/3.2.2/schema_update.sql

@ -79,6 +79,68 @@ CREATE TABLE IF NOT EXISTS ota_package (
CONSTRAINT ota_package_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
);
CREATE TABLE IF NOT EXISTS oauth2_params (
id uuid NOT NULL CONSTRAINT oauth2_params_pkey PRIMARY KEY,
enabled boolean,
tenant_id uuid,
created_time bigint NOT NULL
);
CREATE TABLE IF NOT EXISTS oauth2_registration (
id uuid NOT NULL CONSTRAINT oauth2_registration_pkey PRIMARY KEY,
oauth2_params_id uuid NOT NULL,
created_time bigint NOT NULL,
additional_info varchar,
client_id varchar(255),
client_secret varchar(255),
authorization_uri varchar(255),
token_uri varchar(255),
scope varchar(255),
platforms varchar(255),
user_info_uri varchar(255),
user_name_attribute_name varchar(255),
jwk_set_uri varchar(255),
client_authentication_method varchar(255),
login_button_label varchar(255),
login_button_icon varchar(255),
allow_user_creation boolean,
activate_user boolean,
type varchar(31),
basic_email_attribute_key varchar(31),
basic_first_name_attribute_key varchar(31),
basic_last_name_attribute_key varchar(31),
basic_tenant_name_strategy varchar(31),
basic_tenant_name_pattern varchar(255),
basic_customer_name_pattern varchar(255),
basic_default_dashboard_name varchar(255),
basic_always_full_screen boolean,
custom_url varchar(255),
custom_username varchar(255),
custom_password varchar(255),
custom_send_token boolean,
CONSTRAINT fk_registration_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS oauth2_domain (
id uuid NOT NULL CONSTRAINT oauth2_domain_pkey PRIMARY KEY,
oauth2_params_id uuid NOT NULL,
created_time bigint NOT NULL,
domain_name varchar(255),
domain_scheme varchar(31),
CONSTRAINT fk_domain_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE,
CONSTRAINT oauth2_domain_unq_key UNIQUE (oauth2_params_id, domain_name, domain_scheme)
);
CREATE TABLE IF NOT EXISTS oauth2_mobile (
id uuid NOT NULL CONSTRAINT oauth2_mobile_pkey PRIMARY KEY,
oauth2_params_id uuid NOT NULL,
created_time bigint NOT NULL,
pkg_name varchar(255),
app_secret varchar(2048),
CONSTRAINT fk_mobile_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE,
CONSTRAINT oauth2_mobile_unq_key UNIQUE (oauth2_params_id, pkg_name)
);
ALTER TABLE dashboard
ADD COLUMN IF NOT EXISTS image varchar(1000000);

44
application/src/main/java/org/thingsboard/server/config/CustomOAuth2AuthorizationRequestResolver.java

@ -37,6 +37,9 @@ import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import org.thingsboard.server.dao.oauth2.OAuth2Configuration;
import org.thingsboard.server.dao.oauth2.OAuth2Service;
import org.thingsboard.server.service.security.auth.oauth2.TbOAuth2ParameterNames;
import org.thingsboard.server.service.security.model.token.OAuth2AppTokenFactory;
import org.thingsboard.server.utils.MiscUtils;
import javax.servlet.http.HttpServletRequest;
@ -46,12 +49,13 @@ import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Service
@Slf4j
public class CustomOAuth2AuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {
public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization";
public static final String DEFAULT_LOGIN_PROCESSING_URI = "/login/oauth2/code/";
private static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization";
private static final String DEFAULT_LOGIN_PROCESSING_URI = "/login/oauth2/code/";
private static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId";
private static final char PATH_DELIMITER = '/';
@ -63,6 +67,12 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@Autowired
private OAuth2Service oAuth2Service;
@Autowired
private OAuth2AppTokenFactory oAuth2AppTokenFactory;
@Autowired(required = false)
private OAuth2Configuration oauth2Configuration;
@ -71,7 +81,9 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza
public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
String registrationId = this.resolveRegistrationId(request);
String redirectUriAction = getAction(request, "login");
return resolve(request, registrationId, redirectUriAction);
String appPackage = getAppPackage(request);
String appToken = getAppToken(request);
return resolve(request, registrationId, redirectUriAction, appPackage, appToken);
}
@Override
@ -80,7 +92,9 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza
return null;
}
String redirectUriAction = getAction(request, "authorize");
return resolve(request, registrationId, redirectUriAction);
String appPackage = getAppPackage(request);
String appToken = getAppToken(request);
return resolve(request, registrationId, redirectUriAction, appPackage, appToken);
}
private String getAction(HttpServletRequest request, String defaultAction) {
@ -91,8 +105,16 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza
return action;
}
private String getAppPackage(HttpServletRequest request) {
return request.getParameter("pkg");
}
private String getAppToken(HttpServletRequest request) {
return request.getParameter("appToken");
}
@SuppressWarnings("deprecation")
private OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId, String redirectUriAction) {
private OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId, String redirectUriAction, String appPackage, String appToken) {
if (registrationId == null) {
return null;
}
@ -104,6 +126,18 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza
Map<String, Object> attributes = new HashMap<>();
attributes.put(OAuth2ParameterNames.REGISTRATION_ID, clientRegistration.getRegistrationId());
if (!StringUtils.isEmpty(appPackage)) {
if (StringUtils.isEmpty(appToken)) {
throw new IllegalArgumentException("Invalid application token.");
} else {
String appSecret = this.oAuth2Service.findAppSecret(UUID.fromString(registrationId), appPackage);
if (StringUtils.isEmpty(appSecret)) {
throw new IllegalArgumentException("Invalid package: " + appPackage + ". No application secret found for Client Registration with given application package.");
}
String callbackUrlScheme = this.oAuth2AppTokenFactory.validateTokenAndGetCallbackUrlScheme(appPackage, appToken, appSecret);
attributes.put(TbOAuth2ParameterNames.CALLBACK_URL_SCHEME, callbackUrlScheme);
}
}
OAuth2AuthorizationRequest.Builder builder;
if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(clientRegistration.getAuthorizationGrantType())) {

10
application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java

@ -17,7 +17,6 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.SecurityMode;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
@ -45,14 +44,11 @@ import java.util.Map;
public class Lwm2mController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{securityMode}/{bootstrapServerIs}", method = RequestMethod.GET)
@RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET)
@ResponseBody
public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("securityMode") String strSecurityMode,
@PathVariable("bootstrapServerIs") boolean bootstrapServer) throws ThingsboardException {
checkNotNull(strSecurityMode);
public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("isBootstrapServer") boolean bootstrapServer) throws ThingsboardException {
try {
SecurityMode securityMode = SecurityMode.valueOf(strSecurityMode);
return lwM2MServerSecurityInfoRepository.getServerSecurityInfo(securityMode, bootstrapServer);
return lwM2MServerSecurityInfoRepository.getServerSecurityInfo(bootstrapServer);
} catch (Exception e) {
throw handleException(e);
}

27
application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java

@ -22,12 +22,15 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientsParams;
import org.thingsboard.server.common.data.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.dao.oauth2.OAuth2Configuration;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
@ -49,7 +52,9 @@ public class OAuth2Controller extends BaseController {
@RequestMapping(value = "/noauth/oauth2Clients", method = RequestMethod.POST)
@ResponseBody
public List<OAuth2ClientInfo> getOAuth2Clients(HttpServletRequest request) throws ThingsboardException {
public List<OAuth2ClientInfo> getOAuth2Clients(HttpServletRequest request,
@RequestParam(required = false) String pkgName,
@RequestParam(required = false) String platform) throws ThingsboardException {
try {
if (log.isDebugEnabled()) {
log.debug("Executing getOAuth2Clients: [{}][{}][{}]", request.getScheme(), request.getServerName(), request.getServerPort());
@ -59,7 +64,13 @@ public class OAuth2Controller extends BaseController {
log.debug("Header: {} {}", header, request.getHeader(header));
}
}
return oAuth2Service.getOAuth2Clients(MiscUtils.getScheme(request), MiscUtils.getDomainNameAndPort(request));
PlatformType platformType = null;
if (StringUtils.isNotEmpty(platform)) {
try {
platformType = PlatformType.valueOf(platform);
} catch (Exception e) {}
}
return oAuth2Service.getOAuth2Clients(MiscUtils.getScheme(request), MiscUtils.getDomainNameAndPort(request), pkgName, platformType);
} catch (Exception e) {
throw handleException(e);
}
@ -68,10 +79,10 @@ public class OAuth2Controller extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/oauth2/config", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public OAuth2ClientsParams getCurrentOAuth2Params() throws ThingsboardException {
public OAuth2Info getCurrentOAuth2Info() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_INFO, Operation.READ);
return oAuth2Service.findOAuth2Params();
return oAuth2Service.findOAuth2Info();
} catch (Exception e) {
throw handleException(e);
}
@ -80,11 +91,11 @@ public class OAuth2Controller extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/oauth2/config", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public OAuth2ClientsParams saveOAuth2Params(@RequestBody OAuth2ClientsParams oauth2Params) throws ThingsboardException {
public OAuth2Info saveOAuth2Info(@RequestBody OAuth2Info oauth2Info) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_INFO, Operation.WRITE);
oAuth2Service.saveOAuth2Params(oauth2Params);
return oAuth2Service.findOAuth2Params();
oAuth2Service.saveOAuth2Info(oauth2Info);
return oAuth2Service.findOAuth2Info();
} catch (Exception e) {
throw handleException(e);
}

1
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -199,6 +199,7 @@ public class ThingsboardInstallService {
databaseEntitiesUpgradeService.upgradeDatabase("3.2.2");
dataUpdateService.updateData("3.2.2");
systemDataLoaderService.createOAuth2Templates();
log.info("Updating system data...");
systemDataLoaderService.updateSystemWidgets();

26
application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java

@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.profile.TbDeviceProfileNode;
import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration;
import org.thingsboard.server.common.data.EntityView;
@ -35,6 +36,8 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientsParams;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
@ -45,10 +48,11 @@ import org.thingsboard.server.dao.alarm.AlarmDao;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.oauth2.OAuth2Service;
import org.thingsboard.server.dao.oauth2.OAuth2Utils;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.service.install.InstallScripts;
import java.util.ArrayList;
@ -88,6 +92,9 @@ public class DefaultDataUpdateService implements DataUpdateService {
@Autowired
private AlarmDao alarmDao;
@Autowired
private OAuth2Service oAuth2Service;
@Override
public void updateData(String fromVersion) throws Exception {
switch (fromVersion) {
@ -107,6 +114,7 @@ public class DefaultDataUpdateService implements DataUpdateService {
log.info("Updating data from version 3.2.2 to 3.3.0 ...");
tenantsDefaultEdgeRuleChainUpdater.updateEntities(null);
tenantsAlarmsCustomerUpdater.updateEntities(null);
updateOAuth2Params();
break;
default:
throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
@ -362,4 +370,20 @@ public class DefaultDataUpdateService implements DataUpdateService {
}
}
private void updateOAuth2Params() {
try {
OAuth2ClientsParams oauth2ClientsParams = oAuth2Service.findOAuth2Params();
if (!oauth2ClientsParams.getDomainsParams().isEmpty()) {
log.info("Updating OAuth2 parameters ...");
OAuth2Info oAuth2Info = OAuth2Utils.clientParamsToOAuth2Info(oauth2ClientsParams);
oAuth2Service.saveOAuth2Info(oAuth2Info);
oAuth2Service.saveOAuth2Params(new OAuth2ClientsParams(false, Collections.emptyList()));
log.info("Successfully updated OAuth2 parameters!");
}
}
catch (Exception e) {
log.error("Failed to update OAuth2 parameters", e);
}
}
}

37
application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java

@ -18,7 +18,6 @@ package org.thingsboard.server.service.lwm2m;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.SecurityMode;
import org.eclipse.leshan.core.util.Hex;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
@ -50,40 +49,20 @@ public class LwM2MServerSecurityInfoRepository {
private final LwM2MTransportServerConfig serverConfig;
private final LwM2MTransportBootstrapConfig bootstrapConfig;
/**
* @param securityMode
* @param bootstrapServer
* @return ServerSecurityConfig more value is default: Important - port, host, publicKey
*/
public ServerSecurityConfig getServerSecurityInfo(SecurityMode securityMode, boolean bootstrapServer) {
ServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig, securityMode);
public ServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer) {
ServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig);
result.setBootstrapServerIs(bootstrapServer);
return result;
}
private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig, SecurityMode securityMode) {
private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) {
ServerSecurityConfig bsServ = new ServerSecurityConfig();
bsServ.setServerId(serverConfig.getId());
switch (securityMode) {
case NO_SEC:
bsServ.setHost(serverConfig.getHost());
bsServ.setPort(serverConfig.getPort());
bsServ.setServerPublicKey("");
break;
case PSK:
bsServ.setHost(serverConfig.getSecureHost());
bsServ.setPort(serverConfig.getSecurePort());
bsServ.setServerPublicKey("");
break;
case RPK:
case X509:
bsServ.setHost(serverConfig.getSecureHost());
bsServ.setPort(serverConfig.getSecurePort());
bsServ.setServerPublicKey(getPublicKey(serverConfig.getCertificateAlias(), this.serverConfig.getPublicX(), this.serverConfig.getPublicY()));
break;
default:
break;
}
bsServ.setHost(serverConfig.getHost());
bsServ.setPort(serverConfig.getPort());
bsServ.setSecurityHost(serverConfig.getSecureHost());
bsServ.setSecurityPort(serverConfig.getSecurePort());
bsServ.setServerPublicKey(getPublicKey(serverConfig.getCertificateAlias(), this.serverConfig.getPublicX(), this.serverConfig.getPublicY()));
return bsServ;
}

12
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java

@ -33,8 +33,8 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.IdBased;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
@ -93,9 +93,9 @@ public abstract class AbstractOAuth2ClientMapper {
private final Lock userCreationLock = new ReentrantLock();
protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, OAuth2ClientRegistrationInfo clientRegistration) {
protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, OAuth2Registration registration) {
OAuth2MapperConfig config = clientRegistration.getMapperConfig();
OAuth2MapperConfig config = registration.getMapperConfig();
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, oauth2User.getEmail());
@ -139,9 +139,9 @@ public abstract class AbstractOAuth2ClientMapper {
}
}
if (clientRegistration.getAdditionalInfo() != null &&
clientRegistration.getAdditionalInfo().has("providerName")) {
additionalInfo.put("authProviderName", clientRegistration.getAdditionalInfo().get("providerName").asText());
if (registration.getAdditionalInfo() != null &&
registration.getAdditionalInfo().has("providerName")) {
additionalInfo.put("authProviderName", registration.getAdditionalInfo().get("providerName").asText());
}
user.setAdditionalInfo(additionalInfo);

8
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/BasicOAuth2ClientMapper.java

@ -18,8 +18,8 @@ package org.thingsboard.server.service.security.auth.oauth2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.dao.oauth2.OAuth2User;
import org.thingsboard.server.service.security.model.SecurityUser;
@ -30,12 +30,12 @@ import java.util.Map;
public class BasicOAuth2ClientMapper extends AbstractOAuth2ClientMapper implements OAuth2ClientMapper {
@Override
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, String providerAccessToken, OAuth2ClientRegistrationInfo clientRegistration) {
OAuth2MapperConfig config = clientRegistration.getMapperConfig();
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, String providerAccessToken, OAuth2Registration registration) {
OAuth2MapperConfig config = registration.getMapperConfig();
Map<String, Object> attributes = token.getPrincipal().getAttributes();
String email = BasicMapperUtils.getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey());
OAuth2User oauth2User = BasicMapperUtils.getOAuth2User(email, attributes, config);
return getOrCreateSecurityUserFromOAuth2User(oauth2User, clientRegistration);
return getOrCreateSecurityUserFromOAuth2User(oauth2User, registration);
}
}

8
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CustomOAuth2ClientMapper.java

@ -23,9 +23,9 @@ import org.springframework.security.oauth2.client.authentication.OAuth2Authentic
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2CustomMapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.dao.oauth2.OAuth2User;
import org.thingsboard.server.service.security.model.SecurityUser;
@ -39,10 +39,10 @@ public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme
private RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
@Override
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, String providerAccessToken, OAuth2ClientRegistrationInfo clientRegistration) {
OAuth2MapperConfig config = clientRegistration.getMapperConfig();
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, String providerAccessToken, OAuth2Registration registration) {
OAuth2MapperConfig config = registration.getMapperConfig();
OAuth2User oauth2User = getOAuth2User(token, providerAccessToken, config.getCustom());
return getOrCreateSecurityUserFromOAuth2User(oauth2User, clientRegistration);
return getOrCreateSecurityUserFromOAuth2User(oauth2User, registration);
}
private synchronized OAuth2User getOAuth2User(OAuth2AuthenticationToken token, String providerAccessToken, OAuth2CustomMapperConfig custom) {

8
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/GithubOAuth2ClientMapper.java

@ -23,8 +23,8 @@ import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.dao.oauth2.OAuth2Configuration;
import org.thingsboard.server.dao.oauth2.OAuth2User;
import org.thingsboard.server.service.security.model.SecurityUser;
@ -46,13 +46,13 @@ public class GithubOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme
private OAuth2Configuration oAuth2Configuration;
@Override
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, String providerAccessToken, OAuth2ClientRegistrationInfo clientRegistration) {
OAuth2MapperConfig config = clientRegistration.getMapperConfig();
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, String providerAccessToken, OAuth2Registration registration) {
OAuth2MapperConfig config = registration.getMapperConfig();
Map<String, String> githubMapperConfig = oAuth2Configuration.getGithubMapper();
String email = getEmail(githubMapperConfig.get(EMAIL_URL_KEY), providerAccessToken);
Map<String, Object> attributes = token.getPrincipal().getAttributes();
OAuth2User oAuth2User = BasicMapperUtils.getOAuth2User(email, attributes, config);
return getOrCreateSecurityUserFromOAuth2User(oAuth2User, clientRegistration);
return getOrCreateSecurityUserFromOAuth2User(oAuth2User, registration);
}
private synchronized String getEmail(String emailUrl, String oauth2Token) {

5
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/OAuth2ClientMapper.java

@ -16,9 +16,10 @@
package org.thingsboard.server.service.security.auth.oauth2;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.service.security.model.SecurityUser;
public interface OAuth2ClientMapper {
SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, String providerAccessToken, OAuth2ClientRegistrationInfo clientRegistration);
SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, String providerAccessToken, OAuth2Registration registration);
}

16
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java

@ -18,8 +18,10 @@ package org.thingsboard.server.service.security.auth.oauth2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
@ -51,9 +53,19 @@ public class Oauth2AuthenticationFailureHandler extends SimpleUrlAuthenticationF
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
String baseUrl = this.systemSecurityService.getBaseUrl(TenantId.SYS_TENANT_ID, new CustomerId(EntityId.NULL_UUID), request);
String baseUrl;
String errorPrefix;
OAuth2AuthorizationRequest authorizationRequest = httpCookieOAuth2AuthorizationRequestRepository.loadAuthorizationRequest(request);
String callbackUrlScheme = authorizationRequest.getAttribute(TbOAuth2ParameterNames.CALLBACK_URL_SCHEME);
if (!StringUtils.isEmpty(callbackUrlScheme)) {
baseUrl = callbackUrlScheme + ":";
errorPrefix = "/?error=";
} else {
baseUrl = this.systemSecurityService.getBaseUrl(TenantId.SYS_TENANT_ID, new CustomerId(EntityId.NULL_UUID), request);
errorPrefix = "/login?loginError=";
}
httpCookieOAuth2AuthorizationRequestRepository.removeAuthorizationRequestCookies(request, response);
getRedirectStrategy().sendRedirect(request, response, baseUrl + "/login?loginError=" +
getRedirectStrategy().sendRedirect(request, response, baseUrl + errorPrefix +
URLEncoder.encode(exception.getMessage(), StandardCharsets.UTF_8.toString()));
}
}

27
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java

@ -20,12 +20,14 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.common.data.security.model.JwtToken;
import org.thingsboard.server.dao.oauth2.OAuth2Service;
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
@ -72,17 +74,24 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
String baseUrl = this.systemSecurityService.getBaseUrl(TenantId.SYS_TENANT_ID, new CustomerId(EntityId.NULL_UUID), request);
OAuth2AuthorizationRequest authorizationRequest = httpCookieOAuth2AuthorizationRequestRepository.loadAuthorizationRequest(request);
String callbackUrlScheme = authorizationRequest.getAttribute(TbOAuth2ParameterNames.CALLBACK_URL_SCHEME);
String baseUrl;
if (!StringUtils.isEmpty(callbackUrlScheme)) {
baseUrl = callbackUrlScheme + ":";
} else {
baseUrl = this.systemSecurityService.getBaseUrl(TenantId.SYS_TENANT_ID, new CustomerId(EntityId.NULL_UUID), request);
}
try {
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication;
OAuth2ClientRegistrationInfo clientRegistration = oAuth2Service.findClientRegistrationInfo(UUID.fromString(token.getAuthorizedClientRegistrationId()));
OAuth2Registration registration = oAuth2Service.findRegistration(UUID.fromString(token.getAuthorizedClientRegistrationId()));
OAuth2AuthorizedClient oAuth2AuthorizedClient = oAuth2AuthorizedClientService.loadAuthorizedClient(
token.getAuthorizedClientRegistrationId(),
token.getPrincipal().getName());
OAuth2ClientMapper mapper = oauth2ClientMapperProvider.getOAuth2ClientMapperByType(clientRegistration.getMapperConfig().getType());
OAuth2ClientMapper mapper = oauth2ClientMapperProvider.getOAuth2ClientMapperByType(registration.getMapperConfig().getType());
SecurityUser securityUser = mapper.getOrCreateUserByClientPrincipal(token, oAuth2AuthorizedClient.getAccessToken().getTokenValue(),
clientRegistration);
registration);
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser);
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser);
@ -91,7 +100,13 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
getRedirectStrategy().sendRedirect(request, response, baseUrl + "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken());
} catch (Exception e) {
clearAuthenticationAttributes(request, response);
getRedirectStrategy().sendRedirect(request, response, baseUrl + "/login?loginError=" +
String errorPrefix;
if (!StringUtils.isEmpty(callbackUrlScheme)) {
errorPrefix = "/?error=";
} else {
errorPrefix = "/login?loginError=";
}
getRedirectStrategy().sendRedirect(request, response, baseUrl + errorPrefix +
URLEncoder.encode(e.getMessage(), StandardCharsets.UTF_8.toString()));
}
}

22
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/TbOAuth2ParameterNames.java

@ -0,0 +1,22 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.security.auth.oauth2;
public interface TbOAuth2ParameterNames {
String CALLBACK_URL_SCHEME = "callback_url_scheme";
}

69
application/src/main/java/org/thingsboard/server/service/security/model/token/OAuth2AppTokenFactory.java

@ -0,0 +1,69 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.security.model.token;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class OAuth2AppTokenFactory {
private static final String CALLBACK_URL_SCHEME = "callbackUrlScheme";
private static final long MAX_EXPIRATION_TIME_DIFF_MS = TimeUnit.MINUTES.toMillis(5);
public String validateTokenAndGetCallbackUrlScheme(String appPackage, String appToken, String appSecret) {
Jws<Claims> jwsClaims;
try {
jwsClaims = Jwts.parser().setSigningKey(appSecret).parseClaimsJws(appToken);
}
catch (UnsupportedJwtException | MalformedJwtException | IllegalArgumentException | SignatureException ex) {
throw new IllegalArgumentException("Invalid Application token: ", ex);
} catch (ExpiredJwtException expiredEx) {
throw new IllegalArgumentException("Application token expired", expiredEx);
}
Claims claims = jwsClaims.getBody();
Date expiration = claims.getExpiration();
if (expiration == null) {
throw new IllegalArgumentException("Application token must have expiration date");
}
long timeDiff = expiration.getTime() - System.currentTimeMillis();
if (timeDiff > MAX_EXPIRATION_TIME_DIFF_MS) {
throw new IllegalArgumentException("Application token expiration time can't be longer than 5 minutes");
}
if (!claims.getIssuer().equals(appPackage)) {
throw new IllegalArgumentException("Application token issuer doesn't match application package");
}
String callbackUrlScheme = claims.get(CALLBACK_URL_SCHEME, String.class);
if (StringUtils.isEmpty(callbackUrlScheme)) {
throw new IllegalArgumentException("Application token doesn't have callbackUrlScheme");
}
return callbackUrlScheme;
}
}

21
common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java

@ -16,20 +16,31 @@
package org.thingsboard.server.dao.oauth2;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientsParams;
import org.thingsboard.server.common.data.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientsParams;
import java.util.List;
import java.util.UUID;
public interface OAuth2Service {
List<OAuth2ClientInfo> getOAuth2Clients(String domainScheme, String domainName);
List<OAuth2ClientInfo> getOAuth2Clients(String domainScheme, String domainName, String pkgName, PlatformType platformType);
@Deprecated
void saveOAuth2Params(OAuth2ClientsParams oauth2Params);
@Deprecated
OAuth2ClientsParams findOAuth2Params();
OAuth2ClientRegistrationInfo findClientRegistrationInfo(UUID id);
void saveOAuth2Info(OAuth2Info oauth2Info);
List<OAuth2ClientRegistrationInfo> findAllClientRegistrationInfos();
OAuth2Info findOAuth2Info();
OAuth2Registration findRegistration(UUID id);
List<OAuth2Registration> findAllRegistrations();
String findAppSecret(UUID registrationId, String pkgName);
}

33
common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2DomainId.java

@ -0,0 +1,33 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.UUID;
public class OAuth2DomainId extends UUIDBased {
@JsonCreator
public OAuth2DomainId(@JsonProperty("id") UUID id) {
super(id);
}
public static OAuth2DomainId fromString(String oauth2DomainId) {
return new OAuth2DomainId(UUID.fromString(oauth2DomainId));
}
}

33
common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2MobileId.java

@ -0,0 +1,33 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.UUID;
public class OAuth2MobileId extends UUIDBased {
@JsonCreator
public OAuth2MobileId(@JsonProperty("id") UUID id) {
super(id);
}
public static OAuth2MobileId fromString(String oauth2MobileId) {
return new OAuth2MobileId(UUID.fromString(oauth2MobileId));
}
}

33
common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ParamsId.java

@ -0,0 +1,33 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.UUID;
public class OAuth2ParamsId extends UUIDBased {
@JsonCreator
public OAuth2ParamsId(@JsonProperty("id") UUID id) {
super(id);
}
public static OAuth2ParamsId fromString(String oauth2ParamsId) {
return new OAuth2ParamsId(UUID.fromString(oauth2ParamsId));
}
}

33
common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2RegistrationId.java

@ -0,0 +1,33 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.UUID;
public class OAuth2RegistrationId extends UUIDBased {
@JsonCreator
public OAuth2RegistrationId(@JsonProperty("id") UUID id) {
super(id);
}
public static OAuth2RegistrationId fromString(String oauth2RegistrationId) {
return new OAuth2RegistrationId(UUID.fromString(oauth2RegistrationId));
}
}

4
common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ClientRegistrationId.java → common/data/src/main/java/org/thingsboard/server/common/data/id/deprecated/OAuth2ClientRegistrationId.java

@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.id;
package org.thingsboard.server.common.data.id.deprecated;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.thingsboard.server.common.data.id.UUIDBased;
import java.util.UUID;
@Deprecated
public class OAuth2ClientRegistrationId extends UUIDBased {
@JsonCreator

4
common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ClientRegistrationInfoId.java → common/data/src/main/java/org/thingsboard/server/common/data/id/deprecated/OAuth2ClientRegistrationInfoId.java

@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.id;
package org.thingsboard.server.common.data.id.deprecated;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.thingsboard.server.common.data.id.UUIDBased;
import java.util.UUID;
@Deprecated
public class OAuth2ClientRegistrationInfoId extends UUIDBased {
@JsonCreator

2
common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java

@ -20,7 +20,9 @@ import lombok.Data;
@Data
public class ServerSecurityConfig {
String host;
String securityHost;
Integer port;
Integer securityPort;
String serverPublicKey;
boolean bootstrapServerIs = true;
Integer clientHoldOffTime = 1;

2
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java

@ -20,10 +20,8 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationTemplateId;
import org.thingsboard.server.common.data.id.TenantId;
import java.util.List;

42
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Domain.java

@ -0,0 +1,42 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.OAuth2DomainId;
import org.thingsboard.server.common.data.id.OAuth2ParamsId;
@EqualsAndHashCode(callSuper = true)
@Data
@ToString
@NoArgsConstructor
public class OAuth2Domain extends BaseData<OAuth2DomainId> {
private OAuth2ParamsId oauth2ParamsId;
private String domainName;
private SchemeType domainScheme;
public OAuth2Domain(OAuth2Domain domain) {
super(domain);
this.oauth2ParamsId = domain.oauth2ParamsId;
this.domainName = domain.domainName;
this.domainScheme = domain.domainScheme;
}
}

34
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2DomainInfo.java

@ -0,0 +1,34 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
@EqualsAndHashCode
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class OAuth2DomainInfo {
private SchemeType scheme;
private String name;
}

31
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java

@ -0,0 +1,31 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
import lombok.*;
import java.util.List;
@EqualsAndHashCode
@Data
@ToString
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class OAuth2Info {
private boolean enabled;
private List<OAuth2ParamsInfo> oauth2ParamsInfos;
}

42
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Mobile.java

@ -0,0 +1,42 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.OAuth2MobileId;
import org.thingsboard.server.common.data.id.OAuth2ParamsId;
@EqualsAndHashCode(callSuper = true)
@Data
@ToString
@NoArgsConstructor
public class OAuth2Mobile extends BaseData<OAuth2MobileId> {
private OAuth2ParamsId oauth2ParamsId;
private String pkgName;
private String appSecret;
public OAuth2Mobile(OAuth2Mobile mobile) {
super(mobile);
this.oauth2ParamsId = mobile.oauth2ParamsId;
this.pkgName = mobile.pkgName;
this.appSecret = mobile.appSecret;
}
}

34
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MobileInfo.java

@ -0,0 +1,34 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
@EqualsAndHashCode
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class OAuth2MobileInfo {
private String pkgName;
private String appSecret;
}

40
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Params.java

@ -0,0 +1,40 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.OAuth2ParamsId;
import org.thingsboard.server.common.data.id.TenantId;
@EqualsAndHashCode(callSuper = true)
@Data
@ToString
@NoArgsConstructor
public class OAuth2Params extends BaseData<OAuth2ParamsId> {
private boolean enabled;
private TenantId tenantId;
public OAuth2Params(OAuth2Params oauth2Params) {
super(oauth2Params);
this.enabled = oauth2Params.enabled;
this.tenantId = oauth2Params.tenantId;
}
}

39
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ParamsInfo.java

@ -0,0 +1,39 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.List;
@EqualsAndHashCode
@Data
@ToString
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class OAuth2ParamsInfo {
private List<OAuth2DomainInfo> domainInfos;
private List<OAuth2MobileInfo> mobileInfos;
private List<OAuth2RegistrationInfo> clientRegistrations;
}

79
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Registration.java

@ -0,0 +1,79 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
import org.thingsboard.server.common.data.id.OAuth2ParamsId;
import org.thingsboard.server.common.data.id.OAuth2RegistrationId;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@ToString(exclude = {"clientSecret"})
@NoArgsConstructor
public class OAuth2Registration extends SearchTextBasedWithAdditionalInfo<OAuth2RegistrationId> implements HasName {
private OAuth2ParamsId oauth2ParamsId;
private OAuth2MapperConfig mapperConfig;
private String clientId;
private String clientSecret;
private String authorizationUri;
private String accessTokenUri;
private List<String> scope;
private String userInfoUri;
private String userNameAttributeName;
private String jwkSetUri;
private String clientAuthenticationMethod;
private String loginButtonLabel;
private String loginButtonIcon;
private List<PlatformType> platforms;
public OAuth2Registration(OAuth2Registration registration) {
super(registration);
this.oauth2ParamsId = registration.oauth2ParamsId;
this.mapperConfig = registration.mapperConfig;
this.clientId = registration.clientId;
this.clientSecret = registration.clientSecret;
this.authorizationUri = registration.authorizationUri;
this.accessTokenUri = registration.accessTokenUri;
this.scope = registration.scope;
this.userInfoUri = registration.userInfoUri;
this.userNameAttributeName = registration.userNameAttributeName;
this.jwkSetUri = registration.jwkSetUri;
this.clientAuthenticationMethod = registration.clientAuthenticationMethod;
this.loginButtonLabel = registration.loginButtonLabel;
this.loginButtonIcon = registration.loginButtonIcon;
this.platforms = registration.platforms;
}
@Override
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getName() {
return loginButtonLabel;
}
@Override
public String getSearchText() {
return getName();
}
}

4
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/ClientRegistrationDto.java → common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2RegistrationInfo.java

@ -17,7 +17,6 @@ package org.thingsboard.server.common.data.oauth2;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.*;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationInfoId;
import java.util.List;
@ -27,7 +26,7 @@ import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ClientRegistrationDto {
public class OAuth2RegistrationInfo {
private OAuth2MapperConfig mapperConfig;
private String clientId;
private String clientSecret;
@ -40,5 +39,6 @@ public class ClientRegistrationDto {
private String clientAuthenticationMethod;
private String loginButtonLabel;
private String loginButtonIcon;
private List<PlatformType> platforms;
private JsonNode additionalInfo;
}

20
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/PlatformType.java

@ -0,0 +1,20 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
public enum PlatformType {
WEB, ANDROID, IOS
}

45
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/ClientRegistrationDto.java

@ -0,0 +1,45 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2.deprecated;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.*;
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
import java.util.List;
@Deprecated
@EqualsAndHashCode
@Data
@ToString(exclude = {"clientSecret"})
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ClientRegistrationDto {
private OAuth2MapperConfig mapperConfig;
private String clientId;
private String clientSecret;
private String authorizationUri;
private String accessTokenUri;
private List<String> scope;
private String userInfoUri;
private String userNameAttributeName;
private String jwkSetUri;
private String clientAuthenticationMethod;
private String loginButtonLabel;
private String loginButtonIcon;
private JsonNode additionalInfo;
}

4
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/DomainInfo.java → common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/DomainInfo.java

@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
package org.thingsboard.server.common.data.oauth2.deprecated;
import lombok.*;
import org.thingsboard.server.common.data.oauth2.SchemeType;
@Deprecated
@EqualsAndHashCode
@Data
@ToString

5
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/ExtendedOAuth2ClientRegistrationInfo.java → common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/ExtendedOAuth2ClientRegistrationInfo.java

@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
package org.thingsboard.server.common.data.oauth2.deprecated;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistrationInfo;
@Deprecated
@EqualsAndHashCode(callSuper = true)
@Data
public class ExtendedOAuth2ClientRegistrationInfo extends OAuth2ClientRegistrationInfo {

8
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistration.java → common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientRegistration.java

@ -13,16 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
package org.thingsboard.server.common.data.oauth2.deprecated;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationId;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationInfoId;
import org.thingsboard.server.common.data.id.deprecated.OAuth2ClientRegistrationId;
import org.thingsboard.server.common.data.id.deprecated.OAuth2ClientRegistrationInfoId;
import org.thingsboard.server.common.data.oauth2.SchemeType;
@Deprecated
@EqualsAndHashCode(callSuper = true)
@Data
@ToString

6
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationInfo.java → common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientRegistrationInfo.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
package org.thingsboard.server.common.data.oauth2.deprecated;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@ -22,10 +22,12 @@ import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationInfoId;
import org.thingsboard.server.common.data.id.deprecated.OAuth2ClientRegistrationInfoId;
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
import java.util.List;
@Deprecated
@EqualsAndHashCode(callSuper = true)
@Data
@ToString(exclude = {"clientSecret"})

4
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientsDomainParams.java → common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientsDomainParams.java

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
package org.thingsboard.server.common.data.oauth2.deprecated;
import lombok.*;
import java.util.List;
import java.util.Set;
@Deprecated
@EqualsAndHashCode
@Data
@ToString

4
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientsParams.java → common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientsParams.java

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.oauth2;
package org.thingsboard.server.common.data.oauth2.deprecated;
import lombok.*;
import java.util.List;
import java.util.Set;
@Deprecated
@EqualsAndHashCode
@Data
@ToString

19
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java

@ -482,13 +482,16 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
String title = exchange.getQueryParameter("title");
String version = exchange.getQueryParameter("version");
if (msg.getResponseStatus().equals(TransportProtos.ResponseStatus.SUCCESS)) {
String firmwareId = new UUID(msg.getOtaPackageIdMSB(), msg.getOtaPackageIdLSB()).toString();
if (msg.getTitle().equals(title) && msg.getVersion().equals(version)) {
String firmwareId = new UUID(msg.getOtaPackageIdMSB(), msg.getOtaPackageIdLSB()).toString();
String strChunkSize = exchange.getQueryParameter("size");
String strChunk = exchange.getQueryParameter("chunk");
int chunkSize = StringUtils.isEmpty(strChunkSize) ? 0 : Integer.parseInt(strChunkSize);
int chunk = StringUtils.isEmpty(strChunk) ? 0 : Integer.parseInt(strChunk);
exchange.respond(CoAP.ResponseCode.CONTENT, transportContext.getOtaPackageDataCache().get(firmwareId, chunkSize, chunk));
}
else if (firmwareId != null) {
sendOtaData(exchange, firmwareId);
} else {
exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
}
@ -504,6 +507,20 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
}
}
private void sendOtaData(CoapExchange exchange, String firmwareId) {
Response response = new Response(CoAP.ResponseCode.CONTENT);
byte[] fwData = transportContext.getOtaPackageDataCache().get(firmwareId);
if (fwData != null && fwData.length > 0) {
response.setPayload(fwData);
if (exchange.getRequestOptions().getBlock2() != null) {
int chunkSize = exchange.getRequestOptions().getBlock2().getSzx();
boolean moreFlag = fwData.length > chunkSize;
response.getOptions().setBlock2(chunkSize, moreFlag, 0);
}
exchange.respond(response);
}
}
private static class CoapSessionListener implements SessionMsgListener {
private final CoapTransportResource coapTransportResource;

38
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java

@ -71,10 +71,10 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
@Override
protected void processHandleGet(CoapExchange exchange) {
log.warn("90) processHandleGet [{}]", exchange);
if (exchange.getRequestOptions().getUriPath().size() == 2 &&
(FIRMWARE_UPDATE_COAP_RECOURSE.equals(exchange.getRequestOptions().getUriPath().get(0)) ||
SOFTWARE_UPDATE_COAP_RECOURSE.equals(exchange.getRequestOptions().getUriPath().get(0)))) {
this.sentOtaData(exchange);
if (exchange.getRequestOptions().getUriPath().size() >= 2 &&
(FIRMWARE_UPDATE_COAP_RECOURSE.equals(exchange.getRequestOptions().getUriPath().get(exchange.getRequestOptions().getUriPath().size()-2)) ||
SOFTWARE_UPDATE_COAP_RECOURSE.equals(exchange.getRequestOptions().getUriPath().get(exchange.getRequestOptions().getUriPath().size()-2)))) {
this.sendOtaData(exchange);
}
}
@ -131,23 +131,25 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
}
}
private void sentOtaData(CoapExchange exchange) {
String idStr = exchange.getRequestOptions().getUriPath().get(1);
private void sendOtaData(CoapExchange exchange) {
String idStr = exchange.getRequestOptions().getUriPath().get(exchange.getRequestOptions().getUriPath().size()-1
);
UUID currentId = UUID.fromString(idStr);
if (exchange.getRequestOptions().getBlock2() != null) {
int chunkSize = exchange.getRequestOptions().getBlock2().getSzx();
int chunk = 0;
Response response = new Response(CoAP.ResponseCode.CONTENT);
byte[] fwData = this.getOtaData(currentId);
log.warn("91) read softWare data (length): [{}]", fwData.length);
if (fwData != null && fwData.length > 0) {
response.setPayload(fwData);
Response response = new Response(CoAP.ResponseCode.CONTENT);
byte[] fwData = this.getOtaData(currentId);
log.warn("91) read softWare data (length): [{}]", fwData.length);
if (fwData != null && fwData.length > 0) {
response.setPayload(fwData);
if (exchange.getRequestOptions().getBlock2() != null) {
int chunkSize = exchange.getRequestOptions().getBlock2().getSzx();
boolean moreFlag = fwData.length > chunkSize;
response.getOptions().setBlock2(chunkSize, moreFlag, chunk);
log.warn("92) Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), fwData.length, chunkSize, moreFlag);
exchange.respond(response);
response.getOptions().setBlock2(chunkSize, moreFlag, 0);
log.warn("92) with blokc2 Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), fwData.length, chunkSize, moreFlag);
}
else {
log.warn("92) with block1 Send currentId: [{}], length: [{}], ", currentId.toString(), fwData.length);
}
exchange.respond(response);
}
}

16
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java

@ -37,6 +37,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import static org.eclipse.leshan.core.SecurityMode.NO_SEC;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
@ -138,14 +139,19 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
@Override
public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) {
LwM2mClient lwM2mClient = lwM2mClientsByEndpoint.values().stream().filter(c ->
LwM2mClient lwM2mClient = null;
Predicate<LwM2mClient> isClientFilter = c ->
(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()))
.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB())))
).findAny().orElse(null);
.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB())));
if (this.lwM2mClientsByEndpoint.size() > 0) {
lwM2mClient = this.lwM2mClientsByEndpoint.values().stream().filter(isClientFilter).findAny().orElse(null);
}
if (lwM2mClient == null && this.lwM2mClientsByRegistrationId.size() > 0) {
lwM2mClient = this.lwM2mClientsByRegistrationId.values().stream().filter(isClientFilter).findAny().orElse(null);
}
if (lwM2mClient == null) {
log.warn("Device TimeOut? lwM2mClient is null.");
log.warn("SessionInfo input [{}], lwM2mClientsByEndpoint size: [{}]", sessionInfo, lwM2mClientsByEndpoint.values().size());
log.warn("SessionInfo input [{}], lwM2mClientsByEndpoint size: [{}] lwM2mClientsByRegistrationId: [{}]", sessionInfo, lwM2mClientsByEndpoint.values(), lwM2mClientsByRegistrationId.values());
log.error("", new RuntimeException());
}
return lwM2mClient;

7
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java

@ -203,11 +203,8 @@ public class LwM2mFwSwUpdate {
TbLwM2MWriteReplaceRequest downlink = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(firmwareChunk).timeout(handler.config.getTimeout()).build();
request.sendWriteReplaceRequest(lwM2MClient, downlink, new TbLwM2MWriteReplaceCallback(handler, lwM2MClient, targetIdVer));
} else if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == this.updateStrategy) {
Registration registration = this.getLwM2MClient().getRegistration();
// String api = handler.config.getHostRequests();
String api = "0.0.0.0";
int port = registration.getIdentity().isSecure() ? handler.config.getSecurePort() : handler.config.getPort();
String uri = "coap://" + api + ":" + Integer.valueOf(port) + "/" + FIRMWARE_UPDATE_COAP_RECOURSE + "/" + this.currentId.toString();
String apiFont = "coap://176.36.143.9:5685";
String uri = apiFont + "/" + FIRMWARE_UPDATE_COAP_RECOURSE + "/" + this.currentId.toString();
log.warn("89) coapUri: [{}]", uri);
//TODO: user this.rpcRequest???
TbLwM2MWriteReplaceRequest downlink = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(uri).timeout(handler.config.getTimeout()).build();

19
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.server.rpc;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.server.registration.Registration;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.StringUtils;
@ -111,26 +110,22 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
}
private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequst) {
String id = getIdFromParameters(rpcRequst);
String id = getIdFromParameters(client, rpcRequst);
TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(id).timeout(this.config.getTimeout()).build();
downlinkHandler.sendReadRequest(client, request, new TbLwM2MReadCallback(uplinkHandler, client, id));
}
private String getIdFromParameters(TransportProtos.ToDeviceRpcRequestMsg rpcRequst) {
private String getIdFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequst) {
IdOrKeyRequest requestParams = JacksonUtil.fromString(rpcRequst.getParams(), IdOrKeyRequest.class);
String id;
String targetId;
if (StringUtils.isNotEmpty(requestParams.getKey())) {
id = requestParams.getKey();
targetId = uplinkHandler.getObjectIdByKeyNameFromProfile(client, requestParams.getKey());
} else if (StringUtils.isNotEmpty(requestParams.getId())) {
id = requestParams.getId();
targetId = requestParams.getId();
} else {
throw new IllegalArgumentException("Can't find 'key' or 'id' in the requestParams parameters!");
}
return id;
}
private String getTargetId(LwM2mClient client, String params) {
return targetId;
}
private void sendErrorRpcResponse(TransportProtos.SessionInfoProto sessionInfo, int requestId, String result, String error) {

6
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/LwM2mClientRpcRequest.java

@ -24,8 +24,6 @@ import org.apache.commons.lang3.StringUtils;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.server.registration.Registration;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import java.util.Map;
@ -120,7 +118,7 @@ public class LwM2mClientRpcRequest {
if (this.bodyParams.contains(KEY_NAME_KEY)) {
String targetIdVerStr = this.getValueKeyFromBody(KEY_NAME_KEY);
if (targetIdVerStr != null) {
String targetIdVer = handler.getPresentPathIntoProfile(sessionInfo, targetIdVerStr);
String targetIdVer = handler.getObjectIdByKeyNameFromProfile(sessionInfo, targetIdVerStr);
if (targetIdVer != null) {
this.targetIdVer = targetIdVer;
this.setInfoMsg(String.format("Changed by: key - %s, pathIdVer - %s",
@ -258,7 +256,7 @@ public class LwM2mClientRpcRequest {
int id = Integer.parseInt(k);
paramsIdVer.put(String.valueOf(id), v);
} catch (NumberFormatException e) {
String targetIdVer = serviceImpl.getPresentPathIntoProfile(sessionInfo, k);
String targetIdVer = serviceImpl.getObjectIdByKeyNameFromProfile(sessionInfo, k);
if (targetIdVer != null) {
LwM2mPath lwM2mPath = new LwM2mPath(Objects.requireNonNull(fromVersionedIdToObjectId(targetIdVer)));
paramsIdVer.put(String.valueOf(lwM2mPath.getResourceId()), v);

24
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -376,7 +376,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
log.warn("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList());
msg.getSharedUpdatedList().forEach(tsKvProto -> {
String pathName = tsKvProto.getKv().getKey();
String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);
String pathIdVer = this.getObjectIdByKeyNameFromProfile(sessionInfo, pathName);
Object valueNew = getValueFromKvProto(tsKvProto.getKv());
if ((OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION).equals(pathName)
&& (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())))
@ -987,16 +987,22 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
* Get path to resource from profile equal keyName
*
* @param sessionInfo -
* @param name -
* @param keyName -
* @return -
*/
@Override
public String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
var profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
LwM2mClient lwM2mClient = clientContext.getClientBySessionInfo(sessionInfo);
public String getObjectIdByKeyNameFromProfile(TransportProtos.SessionInfoProto sessionInfo, String keyName) {
return getObjectIdByKeyNameFromProfile(clientContext.getClientBySessionInfo(sessionInfo), keyName);
}
@Override
public String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName) {
Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2mClient.getProfileId());
return profile.getObserveAttr().getKeyName().entrySet().stream()
.filter(e -> e.getValue().equals(name) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().map(Map.Entry::getKey)
.orElse(null);
.filter(e -> e.getValue().equals(keyName) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().orElseThrow(
() -> new IllegalArgumentException(keyName + " is not configured in the device profile!")
).getKey();
}
/**
@ -1033,7 +1039,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
if (lwM2MClient != null) {
log.warn("1) UpdateAttributeFromThingsboard, tsKvProtos [{}]", tsKvProtos);
tsKvProtos.forEach(tsKvProto -> {
String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, tsKvProto.getKv().getKey());
String pathIdVer = this.getObjectIdByKeyNameFromProfile(sessionInfo, tsKvProto.getKv().getKey());
if (pathIdVer != null) {
// #1.1
if (lwM2MClient.getDelayedRequests().containsKey(pathIdVer) && tsKvProto.getTs() > lwM2MClient.getDelayedRequests().get(pathIdVer).getTs()) {

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java

@ -60,7 +60,9 @@ public interface LwM2mUplinkMsgHandler {
void onToTransportUpdateCredentials(TransportProtos.ToTransportUpdateCredentialsProto updateCredentials);
String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name);
String getObjectIdByKeyNameFromProfile(TransportProtos.SessionInfoProto sessionInfo, String name);
String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName);
void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo);

16
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -408,10 +408,20 @@ public class ModelConstants {
/**
* OAuth2 client registration constants.
*/
public static final String OAUTH2_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String OAUTH2_PARAMS_COLUMN_FAMILY_NAME = "oauth2_params";
public static final String OAUTH2_PARAMS_ENABLED_PROPERTY = "enabled";
public static final String OAUTH2_PARAMS_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String OAUTH2_REGISTRATION_COLUMN_FAMILY_NAME = "oauth2_registration";
public static final String OAUTH2_DOMAIN_COLUMN_FAMILY_NAME = "oauth2_domain";
public static final String OAUTH2_MOBILE_COLUMN_FAMILY_NAME = "oauth2_mobile";
public static final String OAUTH2_PARAMS_ID_PROPERTY = "oauth2_params_id";
public static final String OAUTH2_PKG_NAME_PROPERTY = "pkg_name";
public static final String OAUTH2_APP_SECRET_PROPERTY = "app_secret";
public static final String OAUTH2_CLIENT_REGISTRATION_INFO_COLUMN_FAMILY_NAME = "oauth2_client_registration_info";
public static final String OAUTH2_CLIENT_REGISTRATION_COLUMN_FAMILY_NAME = "oauth2_client_registration";
public static final String OAUTH2_CLIENT_REGISTRATION_TO_DOMAIN_COLUMN_FAMILY_NAME = "oauth2_client_registration_to_domain";
public static final String OAUTH2_CLIENT_REGISTRATION_TEMPLATE_COLUMN_FAMILY_NAME = "oauth2_client_registration_template";
public static final String OAUTH2_ENABLED_PROPERTY = "enabled";
public static final String OAUTH2_TEMPLATE_PROVIDER_ID_PROPERTY = "provider_id";
@ -422,8 +432,8 @@ public class ModelConstants {
public static final String OAUTH2_CLIENT_SECRET_PROPERTY = "client_secret";
public static final String OAUTH2_AUTHORIZATION_URI_PROPERTY = "authorization_uri";
public static final String OAUTH2_TOKEN_URI_PROPERTY = "token_uri";
public static final String OAUTH2_REDIRECT_URI_TEMPLATE_PROPERTY = "redirect_uri_template";
public static final String OAUTH2_SCOPE_PROPERTY = "scope";
public static final String OAUTH2_PLATFORMS_PROPERTY = "platforms";
public static final String OAUTH2_USER_INFO_URI_PROPERTY = "user_info_uri";
public static final String OAUTH2_USER_NAME_ATTRIBUTE_NAME_PROPERTY = "user_name_attribute_name";
public static final String OAUTH2_JWK_SET_URI_PROPERTY = "jwk_set_uri";

76
dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2DomainEntity.java

@ -0,0 +1,76 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.OAuth2DomainId;
import org.thingsboard.server.common.data.id.OAuth2ParamsId;
import org.thingsboard.server.common.data.oauth2.OAuth2Domain;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;
import java.util.UUID;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = ModelConstants.OAUTH2_DOMAIN_COLUMN_FAMILY_NAME)
public class OAuth2DomainEntity extends BaseSqlEntity<OAuth2Domain> {
@Column(name = ModelConstants.OAUTH2_PARAMS_ID_PROPERTY)
private UUID oauth2ParamsId;
@Column(name = ModelConstants.OAUTH2_DOMAIN_NAME_PROPERTY)
private String domainName;
@Enumerated(EnumType.STRING)
@Column(name = ModelConstants.OAUTH2_DOMAIN_SCHEME_PROPERTY)
private SchemeType domainScheme;
public OAuth2DomainEntity() {
super();
}
public OAuth2DomainEntity(OAuth2Domain domain) {
if (domain.getId() != null) {
this.setUuid(domain.getId().getId());
}
this.setCreatedTime(domain.getCreatedTime());
if (domain.getOauth2ParamsId() != null) {
this.oauth2ParamsId = domain.getOauth2ParamsId().getId();
}
this.domainName = domain.getDomainName();
this.domainScheme = domain.getDomainScheme();
}
@Override
public OAuth2Domain toData() {
OAuth2Domain domain = new OAuth2Domain();
domain.setId(new OAuth2DomainId(id));
domain.setCreatedTime(createdTime);
domain.setOauth2ParamsId(new OAuth2ParamsId(oauth2ParamsId));
domain.setDomainName(domainName);
domain.setDomainScheme(domainScheme);
return domain;
}
}

72
dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2MobileEntity.java

@ -0,0 +1,72 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.OAuth2MobileId;
import org.thingsboard.server.common.data.id.OAuth2ParamsId;
import org.thingsboard.server.common.data.oauth2.OAuth2Mobile;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.UUID;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = ModelConstants.OAUTH2_MOBILE_COLUMN_FAMILY_NAME)
public class OAuth2MobileEntity extends BaseSqlEntity<OAuth2Mobile> {
@Column(name = ModelConstants.OAUTH2_PARAMS_ID_PROPERTY)
private UUID oauth2ParamsId;
@Column(name = ModelConstants.OAUTH2_PKG_NAME_PROPERTY)
private String pkgName;
@Column(name = ModelConstants.OAUTH2_APP_SECRET_PROPERTY)
private String appSecret;
public OAuth2MobileEntity() {
super();
}
public OAuth2MobileEntity(OAuth2Mobile mobile) {
if (mobile.getId() != null) {
this.setUuid(mobile.getId().getId());
}
this.setCreatedTime(mobile.getCreatedTime());
if (mobile.getOauth2ParamsId() != null) {
this.oauth2ParamsId = mobile.getOauth2ParamsId().getId();
}
this.pkgName = mobile.getPkgName();
this.appSecret = mobile.getAppSecret();
}
@Override
public OAuth2Mobile toData() {
OAuth2Mobile mobile = new OAuth2Mobile();
mobile.setId(new OAuth2MobileId(id));
mobile.setCreatedTime(createdTime);
mobile.setOauth2ParamsId(new OAuth2ParamsId(oauth2ParamsId));
mobile.setPkgName(pkgName);
mobile.setAppSecret(appSecret);
return mobile;
}
}

65
dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ParamsEntity.java

@ -0,0 +1,65 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.id.OAuth2ParamsId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.oauth2.OAuth2Params;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.UUID;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = ModelConstants.OAUTH2_PARAMS_COLUMN_FAMILY_NAME)
@NoArgsConstructor
public class OAuth2ParamsEntity extends BaseSqlEntity<OAuth2Params> {
@Column(name = ModelConstants.OAUTH2_PARAMS_ENABLED_PROPERTY)
private Boolean enabled;
@Column(name = ModelConstants.OAUTH2_PARAMS_TENANT_ID_PROPERTY)
private UUID tenantId;
public OAuth2ParamsEntity(OAuth2Params oauth2Params) {
if (oauth2Params.getId() != null) {
this.setUuid(oauth2Params.getUuidId());
}
this.setCreatedTime(oauth2Params.getCreatedTime());
this.enabled = oauth2Params.isEnabled();
if (oauth2Params.getTenantId() != null) {
this.tenantId = oauth2Params.getTenantId().getId();
}
}
@Override
public OAuth2Params toData() {
OAuth2Params oauth2Params = new OAuth2Params();
oauth2Params.setId(new OAuth2ParamsId(id));
oauth2Params.setCreatedTime(createdTime);
oauth2Params.setTenantId(new TenantId(tenantId));
oauth2Params.setEnabled(enabled);
return oauth2Params;
}
}

221
dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2RegistrationEntity.java

@ -0,0 +1,221 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
import com.fasterxml.jackson.databind.JsonNode;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.id.OAuth2ParamsId;
import org.thingsboard.server.common.data.id.OAuth2RegistrationId;
import org.thingsboard.server.common.data.oauth2.MapperType;
import org.thingsboard.server.common.data.oauth2.OAuth2BasicMapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2CustomMapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.oauth2.TenantNameStrategyType;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;
import java.util.Arrays;
import java.util.Collections;
import java.util.UUID;
import java.util.stream.Collectors;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@TypeDef(name = "json", typeClass = JsonStringType.class)
@Table(name = ModelConstants.OAUTH2_REGISTRATION_COLUMN_FAMILY_NAME)
public class OAuth2RegistrationEntity extends BaseSqlEntity<OAuth2Registration> {
@Column(name = ModelConstants.OAUTH2_PARAMS_ID_PROPERTY)
private UUID oauth2ParamsId;
@Column(name = ModelConstants.OAUTH2_CLIENT_ID_PROPERTY)
private String clientId;
@Column(name = ModelConstants.OAUTH2_CLIENT_SECRET_PROPERTY)
private String clientSecret;
@Column(name = ModelConstants.OAUTH2_AUTHORIZATION_URI_PROPERTY)
private String authorizationUri;
@Column(name = ModelConstants.OAUTH2_TOKEN_URI_PROPERTY)
private String tokenUri;
@Column(name = ModelConstants.OAUTH2_SCOPE_PROPERTY)
private String scope;
@Column(name = ModelConstants.OAUTH2_PLATFORMS_PROPERTY)
private String platforms;
@Column(name = ModelConstants.OAUTH2_USER_INFO_URI_PROPERTY)
private String userInfoUri;
@Column(name = ModelConstants.OAUTH2_USER_NAME_ATTRIBUTE_NAME_PROPERTY)
private String userNameAttributeName;
@Column(name = ModelConstants.OAUTH2_JWK_SET_URI_PROPERTY)
private String jwkSetUri;
@Column(name = ModelConstants.OAUTH2_CLIENT_AUTHENTICATION_METHOD_PROPERTY)
private String clientAuthenticationMethod;
@Column(name = ModelConstants.OAUTH2_LOGIN_BUTTON_LABEL_PROPERTY)
private String loginButtonLabel;
@Column(name = ModelConstants.OAUTH2_LOGIN_BUTTON_ICON_PROPERTY)
private String loginButtonIcon;
@Column(name = ModelConstants.OAUTH2_ALLOW_USER_CREATION_PROPERTY)
private Boolean allowUserCreation;
@Column(name = ModelConstants.OAUTH2_ACTIVATE_USER_PROPERTY)
private Boolean activateUser;
@Enumerated(EnumType.STRING)
@Column(name = ModelConstants.OAUTH2_MAPPER_TYPE_PROPERTY)
private MapperType type;
@Column(name = ModelConstants.OAUTH2_EMAIL_ATTRIBUTE_KEY_PROPERTY)
private String emailAttributeKey;
@Column(name = ModelConstants.OAUTH2_FIRST_NAME_ATTRIBUTE_KEY_PROPERTY)
private String firstNameAttributeKey;
@Column(name = ModelConstants.OAUTH2_LAST_NAME_ATTRIBUTE_KEY_PROPERTY)
private String lastNameAttributeKey;
@Enumerated(EnumType.STRING)
@Column(name = ModelConstants.OAUTH2_TENANT_NAME_STRATEGY_PROPERTY)
private TenantNameStrategyType tenantNameStrategy;
@Column(name = ModelConstants.OAUTH2_TENANT_NAME_PATTERN_PROPERTY)
private String tenantNamePattern;
@Column(name = ModelConstants.OAUTH2_CUSTOMER_NAME_PATTERN_PROPERTY)
private String customerNamePattern;
@Column(name = ModelConstants.OAUTH2_DEFAULT_DASHBOARD_NAME_PROPERTY)
private String defaultDashboardName;
@Column(name = ModelConstants.OAUTH2_ALWAYS_FULL_SCREEN_PROPERTY)
private Boolean alwaysFullScreen;
@Column(name = ModelConstants.OAUTH2_MAPPER_URL_PROPERTY)
private String url;
@Column(name = ModelConstants.OAUTH2_MAPPER_USERNAME_PROPERTY)
private String username;
@Column(name = ModelConstants.OAUTH2_MAPPER_PASSWORD_PROPERTY)
private String password;
@Column(name = ModelConstants.OAUTH2_MAPPER_SEND_TOKEN_PROPERTY)
private Boolean sendToken;
@Type(type = "json")
@Column(name = ModelConstants.OAUTH2_ADDITIONAL_INFO_PROPERTY)
private JsonNode additionalInfo;
public OAuth2RegistrationEntity() {
super();
}
public OAuth2RegistrationEntity(OAuth2Registration registration) {
if (registration.getId() != null) {
this.setUuid(registration.getId().getId());
}
this.setCreatedTime(registration.getCreatedTime());
if (registration.getOauth2ParamsId() != null) {
this.oauth2ParamsId = registration.getOauth2ParamsId().getId();
}
this.clientId = registration.getClientId();
this.clientSecret = registration.getClientSecret();
this.authorizationUri = registration.getAuthorizationUri();
this.tokenUri = registration.getAccessTokenUri();
this.scope = registration.getScope().stream().reduce((result, element) -> result + "," + element).orElse("");
this.platforms = registration.getPlatforms() != null ? registration.getPlatforms().stream().map(Enum::name).reduce((result, element) -> result + "," + element).orElse("") : "";
this.userInfoUri = registration.getUserInfoUri();
this.userNameAttributeName = registration.getUserNameAttributeName();
this.jwkSetUri = registration.getJwkSetUri();
this.clientAuthenticationMethod = registration.getClientAuthenticationMethod();
this.loginButtonLabel = registration.getLoginButtonLabel();
this.loginButtonIcon = registration.getLoginButtonIcon();
this.additionalInfo = registration.getAdditionalInfo();
OAuth2MapperConfig mapperConfig = registration.getMapperConfig();
if (mapperConfig != null) {
this.allowUserCreation = mapperConfig.isAllowUserCreation();
this.activateUser = mapperConfig.isActivateUser();
this.type = mapperConfig.getType();
OAuth2BasicMapperConfig basicConfig = mapperConfig.getBasic();
if (basicConfig != null) {
this.emailAttributeKey = basicConfig.getEmailAttributeKey();
this.firstNameAttributeKey = basicConfig.getFirstNameAttributeKey();
this.lastNameAttributeKey = basicConfig.getLastNameAttributeKey();
this.tenantNameStrategy = basicConfig.getTenantNameStrategy();
this.tenantNamePattern = basicConfig.getTenantNamePattern();
this.customerNamePattern = basicConfig.getCustomerNamePattern();
this.defaultDashboardName = basicConfig.getDefaultDashboardName();
this.alwaysFullScreen = basicConfig.isAlwaysFullScreen();
}
OAuth2CustomMapperConfig customConfig = mapperConfig.getCustom();
if (customConfig != null) {
this.url = customConfig.getUrl();
this.username = customConfig.getUsername();
this.password = customConfig.getPassword();
this.sendToken = customConfig.isSendToken();
}
}
}
@Override
public OAuth2Registration toData() {
OAuth2Registration registration = new OAuth2Registration();
registration.setId(new OAuth2RegistrationId(id));
registration.setCreatedTime(createdTime);
registration.setOauth2ParamsId(new OAuth2ParamsId(oauth2ParamsId));
registration.setAdditionalInfo(additionalInfo);
registration.setMapperConfig(
OAuth2MapperConfig.builder()
.allowUserCreation(allowUserCreation)
.activateUser(activateUser)
.type(type)
.basic(
(type == MapperType.BASIC || type == MapperType.GITHUB) ?
OAuth2BasicMapperConfig.builder()
.emailAttributeKey(emailAttributeKey)
.firstNameAttributeKey(firstNameAttributeKey)
.lastNameAttributeKey(lastNameAttributeKey)
.tenantNameStrategy(tenantNameStrategy)
.tenantNamePattern(tenantNamePattern)
.customerNamePattern(customerNamePattern)
.defaultDashboardName(defaultDashboardName)
.alwaysFullScreen(alwaysFullScreen)
.build()
: null
)
.custom(
type == MapperType.CUSTOM ?
OAuth2CustomMapperConfig.builder()
.url(url)
.username(username)
.password(password)
.sendToken(sendToken)
.build()
: null
)
.build()
);
registration.setClientId(clientId);
registration.setClientSecret(clientSecret);
registration.setAuthorizationUri(authorizationUri);
registration.setAccessTokenUri(tokenUri);
registration.setScope(Arrays.asList(scope.split(",")));
registration.setPlatforms(StringUtils.isNotEmpty(platforms) ? Arrays.stream(platforms.split(","))
.map(str -> PlatformType.valueOf(str)).collect(Collectors.toList()) : Collections.emptyList());
registration.setUserInfoUri(userInfoUri);
registration.setUserNameAttributeName(userNameAttributeName);
registration.setJwkSetUri(jwkSetUri);
registration.setClientAuthenticationMethod(clientAuthenticationMethod);
registration.setLoginButtonLabel(loginButtonLabel);
registration.setLoginButtonIcon(loginButtonIcon);
return registration;
}
}

7
dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractOAuth2ClientRegistrationInfoEntity.java → dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/AbstractOAuth2ClientRegistrationInfoEntity.java

@ -13,22 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
package org.thingsboard.server.dao.model.sql.deprecated;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationInfoId;
import org.thingsboard.server.common.data.id.deprecated.OAuth2ClientRegistrationInfoId;
import org.thingsboard.server.common.data.oauth2.*;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.model.sql.deprecated.OAuth2ClientRegistrationInfoEntity;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.*;
import java.util.Arrays;
@Deprecated
@Data
@EqualsAndHashCode(callSuper = true)
@TypeDef(name = "json", typeClass = JsonStringType.class)

5
dao/src/main/java/org/thingsboard/server/dao/model/sql/ExtendedOAuth2ClientRegistrationInfoEntity.java → dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/ExtendedOAuth2ClientRegistrationInfoEntity.java

@ -13,13 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
package org.thingsboard.server.dao.model.sql.deprecated;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.oauth2.ExtendedOAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.ExtendedOAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.SchemeType;
@Deprecated
@Data
@EqualsAndHashCode(callSuper = true)
public class ExtendedOAuth2ClientRegistrationInfoEntity extends AbstractOAuth2ClientRegistrationInfoEntity<ExtendedOAuth2ClientRegistrationInfo> {

9
dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ClientRegistrationEntity.java → dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/OAuth2ClientRegistrationEntity.java

@ -13,22 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
package org.thingsboard.server.dao.model.sql.deprecated;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationId;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationInfoId;
import org.thingsboard.server.common.data.id.deprecated.OAuth2ClientRegistrationId;
import org.thingsboard.server.common.data.id.deprecated.OAuth2ClientRegistrationInfoId;
import org.thingsboard.server.common.data.oauth2.*;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistration;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.*;
import java.util.Arrays;
import java.util.UUID;
@Deprecated
@Data
@EqualsAndHashCode(callSuper = true)
@Entity

5
dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ClientRegistrationInfoEntity.java → dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/OAuth2ClientRegistrationInfoEntity.java

@ -13,18 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
package org.thingsboard.server.dao.model.sql.deprecated;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Entity;
import javax.persistence.Table;
@Deprecated
@Data
@EqualsAndHashCode(callSuper = true)
@Entity

32
dao/src/main/java/org/thingsboard/server/dao/oauth2/HybridClientRegistrationRepository.java

@ -21,7 +21,7 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import java.util.UUID;
@ -34,25 +34,25 @@ public class HybridClientRegistrationRepository implements ClientRegistrationRep
@Override
public ClientRegistration findByRegistrationId(String registrationId) {
OAuth2ClientRegistrationInfo oAuth2ClientRegistrationInfo = oAuth2Service.findClientRegistrationInfo(UUID.fromString(registrationId));
return oAuth2ClientRegistrationInfo == null ?
null : toSpringClientRegistration(oAuth2ClientRegistrationInfo);
OAuth2Registration registration = oAuth2Service.findRegistration(UUID.fromString(registrationId));
return registration == null ?
null : toSpringClientRegistration(registration);
}
private ClientRegistration toSpringClientRegistration(OAuth2ClientRegistrationInfo localClientRegistration){
String registrationId = localClientRegistration.getUuidId().toString();
private ClientRegistration toSpringClientRegistration(OAuth2Registration registration){
String registrationId = registration.getUuidId().toString();
return ClientRegistration.withRegistrationId(registrationId)
.clientName(localClientRegistration.getName())
.clientId(localClientRegistration.getClientId())
.authorizationUri(localClientRegistration.getAuthorizationUri())
.clientSecret(localClientRegistration.getClientSecret())
.tokenUri(localClientRegistration.getAccessTokenUri())
.scope(localClientRegistration.getScope())
.clientName(registration.getName())
.clientId(registration.getClientId())
.authorizationUri(registration.getAuthorizationUri())
.clientSecret(registration.getClientSecret())
.tokenUri(registration.getAccessTokenUri())
.scope(registration.getScope())
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.userInfoUri(localClientRegistration.getUserInfoUri())
.userNameAttributeName(localClientRegistration.getUserNameAttributeName())
.jwkSetUri(localClientRegistration.getJwkSetUri())
.clientAuthenticationMethod(new ClientAuthenticationMethod(localClientRegistration.getClientAuthenticationMethod()))
.userInfoUri(registration.getUserInfoUri())
.userNameAttributeName(registration.getUserNameAttributeName())
.jwkSetUri(registration.getJwkSetUri())
.clientAuthenticationMethod(new ClientAuthenticationMethod(registration.getClientAuthenticationMethod()))
.redirectUri(defaultRedirectUriTemplate)
.build();
}

28
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2DomainDao.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.oauth2;
import org.thingsboard.server.common.data.oauth2.OAuth2Domain;
import org.thingsboard.server.dao.Dao;
import java.util.List;
import java.util.UUID;
public interface OAuth2DomainDao extends Dao<OAuth2Domain> {
List<OAuth2Domain> findByOAuth2ParamsId(UUID oauth2ParamsId);
}

28
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2MobileDao.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.oauth2;
import org.thingsboard.server.common.data.oauth2.OAuth2Mobile;
import org.thingsboard.server.dao.Dao;
import java.util.List;
import java.util.UUID;
public interface OAuth2MobileDao extends Dao<OAuth2Mobile> {
List<OAuth2Mobile> findByOAuth2ParamsId(UUID oauth2ParamsId);
}

23
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ParamsDao.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.oauth2;
import org.thingsboard.server.common.data.oauth2.OAuth2Params;
import org.thingsboard.server.dao.Dao;
public interface OAuth2ParamsDao extends Dao<OAuth2Params> {
void deleteAll();
}

34
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2RegistrationDao.java

@ -0,0 +1,34 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.oauth2;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.dao.Dao;
import java.util.List;
import java.util.UUID;
public interface OAuth2RegistrationDao extends Dao<OAuth2Registration> {
List<OAuth2Registration> findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(List<SchemeType> domainSchemes, String domainName, String pkgName, PlatformType platformType);
List<OAuth2Registration> findByOAuth2ParamsId(UUID oauth2ParamsId);
String findAppSecret(UUID id, String pkgName);
}

252
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java

@ -19,14 +19,44 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.oauth2.*;
import org.thingsboard.server.common.data.oauth2.MapperType;
import org.thingsboard.server.common.data.oauth2.OAuth2BasicMapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2CustomMapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2Domain;
import org.thingsboard.server.common.data.oauth2.OAuth2DomainInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2Mobile;
import org.thingsboard.server.common.data.oauth2.OAuth2MobileInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2Params;
import org.thingsboard.server.common.data.oauth2.OAuth2ParamsInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.common.data.oauth2.OAuth2RegistrationInfo;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.common.data.oauth2.TenantNameStrategyType;
import org.thingsboard.server.common.data.oauth2.deprecated.ClientRegistrationDto;
import org.thingsboard.server.common.data.oauth2.deprecated.DomainInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.ExtendedOAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistration;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientsDomainParams;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientsParams;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.oauth2.deprecated.OAuth2ClientRegistrationDao;
import org.thingsboard.server.dao.oauth2.deprecated.OAuth2ClientRegistrationInfoDao;
import javax.transaction.Transactional;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@ -45,10 +75,18 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
private OAuth2ClientRegistrationInfoDao clientRegistrationInfoDao;
@Autowired
private OAuth2ClientRegistrationDao clientRegistrationDao;
@Autowired
private OAuth2ParamsDao oauth2ParamsDao;
@Autowired
private OAuth2RegistrationDao oauth2RegistrationDao;
@Autowired
private OAuth2DomainDao oauth2DomainDao;
@Autowired
private OAuth2MobileDao oauth2MobileDao;
@Override
public List<OAuth2ClientInfo> getOAuth2Clients(String domainSchemeStr, String domainName) {
log.trace("Executing getOAuth2Clients [{}://{}]", domainSchemeStr, domainName);
public List<OAuth2ClientInfo> getOAuth2Clients(String domainSchemeStr, String domainName, String pkgName, PlatformType platformType) {
log.trace("Executing getOAuth2Clients [{}://{}] pkgName=[{}] platformType=[{}]", domainSchemeStr, domainName, pkgName, platformType);
if (domainSchemeStr == null) {
throw new IncorrectParameterException(INCORRECT_DOMAIN_SCHEME);
}
@ -59,12 +97,14 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
throw new IncorrectParameterException(INCORRECT_DOMAIN_SCHEME);
}
validateString(domainName, INCORRECT_DOMAIN_NAME + domainName);
return clientRegistrationInfoDao.findByDomainSchemesAndDomainName(Arrays.asList(domainScheme, SchemeType.MIXED), domainName).stream()
.filter(OAuth2ClientRegistrationInfo::isEnabled)
return oauth2RegistrationDao.findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(
Arrays.asList(domainScheme, SchemeType.MIXED), domainName, pkgName, platformType)
.stream()
.map(OAuth2Utils::toClientInfo)
.collect(Collectors.toList());
}
@Deprecated
@Override
@Transactional
public void saveOAuth2Params(OAuth2ClientsParams oauth2Params) {
@ -85,6 +125,33 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
});
}
@Override
@Transactional
public void saveOAuth2Info(OAuth2Info oauth2Info) {
log.trace("Executing saveOAuth2Info [{}]", oauth2Info);
oauth2InfoValidator.accept(oauth2Info);
oauth2ParamsDao.deleteAll();
oauth2Info.getOauth2ParamsInfos().forEach(oauth2ParamsInfo -> {
OAuth2Params oauth2Params = OAuth2Utils.infoToOAuth2Params(oauth2Info);
OAuth2Params savedOauth2Params = oauth2ParamsDao.save(TenantId.SYS_TENANT_ID, oauth2Params);
oauth2ParamsInfo.getClientRegistrations().forEach(registrationInfo -> {
OAuth2Registration registration = OAuth2Utils.toOAuth2Registration(savedOauth2Params.getId(), registrationInfo);
oauth2RegistrationDao.save(TenantId.SYS_TENANT_ID, registration);
});
oauth2ParamsInfo.getDomainInfos().forEach(domainInfo -> {
OAuth2Domain domain = OAuth2Utils.toOAuth2Domain(savedOauth2Params.getId(), domainInfo);
oauth2DomainDao.save(TenantId.SYS_TENANT_ID, domain);
});
if (oauth2ParamsInfo.getMobileInfos() != null) {
oauth2ParamsInfo.getMobileInfos().forEach(mobileInfo -> {
OAuth2Mobile mobile = OAuth2Utils.toOAuth2Mobile(savedOauth2Params.getId(), mobileInfo);
oauth2MobileDao.save(TenantId.SYS_TENANT_ID, mobile);
});
}
});
}
@Deprecated
@Override
public OAuth2ClientsParams findOAuth2Params() {
log.trace("Executing findOAuth2Params");
@ -93,16 +160,42 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
}
@Override
public OAuth2ClientRegistrationInfo findClientRegistrationInfo(UUID id) {
log.trace("Executing findClientRegistrationInfo [{}]", id);
public OAuth2Info findOAuth2Info() {
log.trace("Executing findOAuth2Info");
OAuth2Info oauth2Info = new OAuth2Info();
List<OAuth2Params> oauth2ParamsList = oauth2ParamsDao.find(TenantId.SYS_TENANT_ID);
oauth2Info.setEnabled(oauth2ParamsList.stream().anyMatch(param -> param.isEnabled()));
List<OAuth2ParamsInfo> oauth2ParamsInfos = new ArrayList<>();
oauth2Info.setOauth2ParamsInfos(oauth2ParamsInfos);
oauth2ParamsList.stream().sorted(Comparator.comparing(BaseData::getUuidId)).forEach(oauth2Params -> {
List<OAuth2Registration> registrations = oauth2RegistrationDao.findByOAuth2ParamsId(oauth2Params.getId().getId());
List<OAuth2Domain> domains = oauth2DomainDao.findByOAuth2ParamsId(oauth2Params.getId().getId());
List<OAuth2Mobile> mobiles = oauth2MobileDao.findByOAuth2ParamsId(oauth2Params.getId().getId());
oauth2ParamsInfos.add(OAuth2Utils.toOAuth2ParamsInfo(registrations, domains, mobiles));
});
return oauth2Info;
}
@Override
public OAuth2Registration findRegistration(UUID id) {
log.trace("Executing findRegistration [{}]", id);
validateId(id, INCORRECT_CLIENT_REGISTRATION_ID + id);
return oauth2RegistrationDao.findById(null, id);
}
@Override
public String findAppSecret(UUID id, String pkgName) {
log.trace("Executing findAppSecret [{}][{}]", id, pkgName);
validateId(id, INCORRECT_CLIENT_REGISTRATION_ID + id);
return clientRegistrationInfoDao.findById(null, id);
validateString(pkgName, "Incorrect package name");
return oauth2RegistrationDao.findAppSecret(id, pkgName);
}
@Override
public List<OAuth2ClientRegistrationInfo> findAllClientRegistrationInfos() {
log.trace("Executing findAllClientRegistrationInfos");
return clientRegistrationInfoDao.findAll();
public List<OAuth2Registration> findAllRegistrations() {
log.trace("Executing findAllRegistrations");
return oauth2RegistrationDao.find(TenantId.SYS_TENANT_ID);
}
private final Consumer<OAuth2ClientsParams> clientParamsValidator = oauth2Params -> {
@ -212,4 +305,139 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
}
}
};
private final Consumer<OAuth2Info> oauth2InfoValidator = oauth2Info -> {
if (oauth2Info == null
|| oauth2Info.getOauth2ParamsInfos() == null) {
throw new DataValidationException("OAuth2 param infos should be specified!");
}
for (OAuth2ParamsInfo oauth2Params : oauth2Info.getOauth2ParamsInfos()) {
if (oauth2Params.getDomainInfos() == null
|| oauth2Params.getDomainInfos().isEmpty()) {
throw new DataValidationException("List of domain configuration should be specified!");
}
for (OAuth2DomainInfo domainInfo : oauth2Params.getDomainInfos()) {
if (StringUtils.isEmpty(domainInfo.getName())) {
throw new DataValidationException("Domain name should be specified!");
}
if (domainInfo.getScheme() == null) {
throw new DataValidationException("Domain scheme should be specified!");
}
}
oauth2Params.getDomainInfos().stream()
.collect(Collectors.groupingBy(OAuth2DomainInfo::getName))
.forEach((domainName, domainInfos) -> {
if (domainInfos.size() > 1 && domainInfos.stream().anyMatch(domainInfo -> domainInfo.getScheme() == SchemeType.MIXED)) {
throw new DataValidationException("MIXED scheme type shouldn't be combined with another scheme type!");
}
domainInfos.stream()
.collect(Collectors.groupingBy(OAuth2DomainInfo::getScheme))
.forEach((schemeType, domainInfosBySchemeType) -> {
if (domainInfosBySchemeType.size() > 1) {
throw new DataValidationException("Domain name and protocol must be unique within OAuth2 parameters!");
}
});
});
if (oauth2Params.getMobileInfos() != null) {
for (OAuth2MobileInfo mobileInfo : oauth2Params.getMobileInfos()) {
if (StringUtils.isEmpty(mobileInfo.getPkgName())) {
throw new DataValidationException("Package should be specified!");
}
if (StringUtils.isEmpty(mobileInfo.getAppSecret())) {
throw new DataValidationException("Application secret should be specified!");
}
if (mobileInfo.getAppSecret().length() < 16) {
throw new DataValidationException("Application secret should be at least 16 characters!");
}
}
oauth2Params.getMobileInfos().stream()
.collect(Collectors.groupingBy(OAuth2MobileInfo::getPkgName))
.forEach((pkgName, mobileInfos) -> {
if (mobileInfos.size() > 1) {
throw new DataValidationException("Mobile app package name must be unique within OAuth2 parameters!");
}
});
}
if (oauth2Params.getClientRegistrations() == null || oauth2Params.getClientRegistrations().isEmpty()) {
throw new DataValidationException("Client registrations should be specified!");
}
for (OAuth2RegistrationInfo clientRegistration : oauth2Params.getClientRegistrations()) {
if (StringUtils.isEmpty(clientRegistration.getClientId())) {
throw new DataValidationException("Client ID should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getClientSecret())) {
throw new DataValidationException("Client secret should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getAuthorizationUri())) {
throw new DataValidationException("Authorization uri should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getAccessTokenUri())) {
throw new DataValidationException("Token uri should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getScope())) {
throw new DataValidationException("Scope should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getUserInfoUri())) {
throw new DataValidationException("User info uri should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getUserNameAttributeName())) {
throw new DataValidationException("User name attribute name should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getClientAuthenticationMethod())) {
throw new DataValidationException("Client authentication method should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getLoginButtonLabel())) {
throw new DataValidationException("Login button label should be specified!");
}
OAuth2MapperConfig mapperConfig = clientRegistration.getMapperConfig();
if (mapperConfig == null) {
throw new DataValidationException("Mapper config should be specified!");
}
if (mapperConfig.getType() == null) {
throw new DataValidationException("Mapper config type should be specified!");
}
if (mapperConfig.getType() == MapperType.BASIC) {
OAuth2BasicMapperConfig basicConfig = mapperConfig.getBasic();
if (basicConfig == null) {
throw new DataValidationException("Basic config should be specified!");
}
if (StringUtils.isEmpty(basicConfig.getEmailAttributeKey())) {
throw new DataValidationException("Email attribute key should be specified!");
}
if (basicConfig.getTenantNameStrategy() == null) {
throw new DataValidationException("Tenant name strategy should be specified!");
}
if (basicConfig.getTenantNameStrategy() == TenantNameStrategyType.CUSTOM
&& StringUtils.isEmpty(basicConfig.getTenantNamePattern())) {
throw new DataValidationException("Tenant name pattern should be specified!");
}
}
if (mapperConfig.getType() == MapperType.GITHUB) {
OAuth2BasicMapperConfig basicConfig = mapperConfig.getBasic();
if (basicConfig == null) {
throw new DataValidationException("Basic config should be specified!");
}
if (!StringUtils.isEmpty(basicConfig.getEmailAttributeKey())) {
throw new DataValidationException("Email attribute key cannot be configured for GITHUB mapper type!");
}
if (basicConfig.getTenantNameStrategy() == null) {
throw new DataValidationException("Tenant name strategy should be specified!");
}
if (basicConfig.getTenantNameStrategy() == TenantNameStrategyType.CUSTOM
&& StringUtils.isEmpty(basicConfig.getTenantNamePattern())) {
throw new DataValidationException("Tenant name pattern should be specified!");
}
}
if (mapperConfig.getType() == MapperType.CUSTOM) {
OAuth2CustomMapperConfig customConfig = mapperConfig.getCustom();
if (customConfig == null) {
throw new DataValidationException("Custom config should be specified!");
}
if (StringUtils.isEmpty(customConfig.getUrl())) {
throw new DataValidationException("Custom mapper URL should be specified!");
}
}
}
}
};
}

147
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java

@ -15,19 +15,30 @@
*/
package org.thingsboard.server.dao.oauth2;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationInfoId;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.OAuth2ParamsId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.deprecated.OAuth2ClientRegistrationInfoId;
import org.thingsboard.server.common.data.oauth2.*;
import org.thingsboard.server.common.data.oauth2.deprecated.ClientRegistrationDto;
import org.thingsboard.server.common.data.oauth2.deprecated.DomainInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.ExtendedOAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistration;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientsDomainParams;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientsParams;
import java.util.*;
import java.util.stream.Collectors;
public class OAuth2Utils {
public static final String OAUTH2_AUTHORIZATION_PATH_TEMPLATE = "/oauth2/authorization/%s";
public static OAuth2ClientInfo toClientInfo(OAuth2ClientRegistrationInfo clientRegistrationInfo) {
public static OAuth2ClientInfo toClientInfo(OAuth2Registration registration) {
OAuth2ClientInfo client = new OAuth2ClientInfo();
client.setName(clientRegistrationInfo.getLoginButtonLabel());
client.setUrl(String.format(OAUTH2_AUTHORIZATION_PATH_TEMPLATE, clientRegistrationInfo.getUuidId().toString()));
client.setIcon(clientRegistrationInfo.getLoginButtonIcon());
client.setName(registration.getLoginButtonLabel());
client.setUrl(String.format(OAUTH2_AUTHORIZATION_PATH_TEMPLATE, registration.getUuidId().toString()));
client.setIcon(registration.getLoginButtonIcon());
return client;
}
@ -99,4 +110,130 @@ public class OAuth2Utils {
clientRegistration.setDomainScheme(domainScheme);
return clientRegistration;
}
public static OAuth2ParamsInfo toOAuth2ParamsInfo(List<OAuth2Registration> registrations, List<OAuth2Domain> domains, List<OAuth2Mobile> mobiles) {
OAuth2ParamsInfo oauth2ParamsInfo = new OAuth2ParamsInfo();
oauth2ParamsInfo.setClientRegistrations(registrations.stream().sorted(Comparator.comparing(BaseData::getUuidId)).map(OAuth2Utils::toOAuth2RegistrationInfo).collect(Collectors.toList()));
oauth2ParamsInfo.setDomainInfos(domains.stream().sorted(Comparator.comparing(BaseData::getUuidId)).map(OAuth2Utils::toOAuth2DomainInfo).collect(Collectors.toList()));
oauth2ParamsInfo.setMobileInfos(mobiles.stream().sorted(Comparator.comparing(BaseData::getUuidId)).map(OAuth2Utils::toOAuth2MobileInfo).collect(Collectors.toList()));
return oauth2ParamsInfo;
}
public static OAuth2RegistrationInfo toOAuth2RegistrationInfo(OAuth2Registration registration) {
return OAuth2RegistrationInfo.builder()
.mapperConfig(registration.getMapperConfig())
.clientId(registration.getClientId())
.clientSecret(registration.getClientSecret())
.authorizationUri(registration.getAuthorizationUri())
.accessTokenUri(registration.getAccessTokenUri())
.scope(registration.getScope())
.platforms(registration.getPlatforms())
.userInfoUri(registration.getUserInfoUri())
.userNameAttributeName(registration.getUserNameAttributeName())
.jwkSetUri(registration.getJwkSetUri())
.clientAuthenticationMethod(registration.getClientAuthenticationMethod())
.loginButtonLabel(registration.getLoginButtonLabel())
.loginButtonIcon(registration.getLoginButtonIcon())
.additionalInfo(registration.getAdditionalInfo())
.build();
}
public static OAuth2DomainInfo toOAuth2DomainInfo(OAuth2Domain domain) {
return OAuth2DomainInfo.builder()
.name(domain.getDomainName())
.scheme(domain.getDomainScheme())
.build();
}
public static OAuth2MobileInfo toOAuth2MobileInfo(OAuth2Mobile mobile) {
return OAuth2MobileInfo.builder()
.pkgName(mobile.getPkgName())
.appSecret(mobile.getAppSecret())
.build();
}
public static OAuth2Params infoToOAuth2Params(OAuth2Info oauth2Info) {
OAuth2Params oauth2Params = new OAuth2Params();
oauth2Params.setEnabled(oauth2Info.isEnabled());
oauth2Params.setTenantId(TenantId.SYS_TENANT_ID);
return oauth2Params;
}
public static OAuth2Registration toOAuth2Registration(OAuth2ParamsId oauth2ParamsId, OAuth2RegistrationInfo registrationInfo) {
OAuth2Registration registration = new OAuth2Registration();
registration.setOauth2ParamsId(oauth2ParamsId);
registration.setMapperConfig(registrationInfo.getMapperConfig());
registration.setClientId(registrationInfo.getClientId());
registration.setClientSecret(registrationInfo.getClientSecret());
registration.setAuthorizationUri(registrationInfo.getAuthorizationUri());
registration.setAccessTokenUri(registrationInfo.getAccessTokenUri());
registration.setScope(registrationInfo.getScope());
registration.setPlatforms(registrationInfo.getPlatforms());
registration.setUserInfoUri(registrationInfo.getUserInfoUri());
registration.setUserNameAttributeName(registrationInfo.getUserNameAttributeName());
registration.setJwkSetUri(registrationInfo.getJwkSetUri());
registration.setClientAuthenticationMethod(registrationInfo.getClientAuthenticationMethod());
registration.setLoginButtonLabel(registrationInfo.getLoginButtonLabel());
registration.setLoginButtonIcon(registrationInfo.getLoginButtonIcon());
registration.setAdditionalInfo(registrationInfo.getAdditionalInfo());
return registration;
}
public static OAuth2Domain toOAuth2Domain(OAuth2ParamsId oauth2ParamsId, OAuth2DomainInfo domainInfo) {
OAuth2Domain domain = new OAuth2Domain();
domain.setOauth2ParamsId(oauth2ParamsId);
domain.setDomainName(domainInfo.getName());
domain.setDomainScheme(domainInfo.getScheme());
return domain;
}
public static OAuth2Mobile toOAuth2Mobile(OAuth2ParamsId oauth2ParamsId, OAuth2MobileInfo mobileInfo) {
OAuth2Mobile mobile = new OAuth2Mobile();
mobile.setOauth2ParamsId(oauth2ParamsId);
mobile.setPkgName(mobileInfo.getPkgName());
mobile.setAppSecret(mobileInfo.getAppSecret());
return mobile;
}
@Deprecated
public static OAuth2Info clientParamsToOAuth2Info(OAuth2ClientsParams clientsParams) {
OAuth2Info oauth2Info = new OAuth2Info();
oauth2Info.setEnabled(clientsParams.isEnabled());
oauth2Info.setOauth2ParamsInfos(clientsParams.getDomainsParams().stream().map(OAuth2Utils::clientsDomainParamsToOAuth2ParamsInfo).collect(Collectors.toList()));
return oauth2Info;
}
private static OAuth2ParamsInfo clientsDomainParamsToOAuth2ParamsInfo(OAuth2ClientsDomainParams clientsDomainParams) {
OAuth2ParamsInfo oauth2ParamsInfo = new OAuth2ParamsInfo();
oauth2ParamsInfo.setMobileInfos(Collections.emptyList());
oauth2ParamsInfo.setClientRegistrations(clientsDomainParams.getClientRegistrations().stream().map(OAuth2Utils::clientRegistrationDtoToOAuth2RegistrationInfo).collect(Collectors.toList()));
oauth2ParamsInfo.setDomainInfos(clientsDomainParams.getDomainInfos().stream().map(OAuth2Utils::domainInfoToOAuth2DomainInfo).collect(Collectors.toList()));
return oauth2ParamsInfo;
}
private static OAuth2RegistrationInfo clientRegistrationDtoToOAuth2RegistrationInfo(ClientRegistrationDto clientRegistrationDto) {
return OAuth2RegistrationInfo.builder()
.mapperConfig(clientRegistrationDto.getMapperConfig())
.clientId(clientRegistrationDto.getClientId())
.clientSecret(clientRegistrationDto.getClientSecret())
.authorizationUri(clientRegistrationDto.getAuthorizationUri())
.accessTokenUri(clientRegistrationDto.getAccessTokenUri())
.scope(clientRegistrationDto.getScope())
.userInfoUri(clientRegistrationDto.getUserInfoUri())
.userNameAttributeName(clientRegistrationDto.getUserNameAttributeName())
.jwkSetUri(clientRegistrationDto.getJwkSetUri())
.clientAuthenticationMethod(clientRegistrationDto.getClientAuthenticationMethod())
.loginButtonLabel(clientRegistrationDto.getLoginButtonLabel())
.loginButtonIcon(clientRegistrationDto.getLoginButtonIcon())
.additionalInfo(clientRegistrationDto.getAdditionalInfo())
.platforms(Collections.emptyList())
.build();
}
private static OAuth2DomainInfo domainInfoToOAuth2DomainInfo(DomainInfo domainInfo) {
return OAuth2DomainInfo.builder()
.name(domainInfo.getName())
.scheme(domainInfo.getScheme())
.build();
}
}

5
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientRegistrationDao.java → dao/src/main/java/org/thingsboard/server/dao/oauth2/deprecated/OAuth2ClientRegistrationDao.java

@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.oauth2;
package org.thingsboard.server.dao.oauth2.deprecated;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistration;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistration;
import org.thingsboard.server.dao.Dao;
@Deprecated
public interface OAuth2ClientRegistrationDao extends Dao<OAuth2ClientRegistration> {
void deleteAll();
}

8
dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientRegistrationInfoDao.java → dao/src/main/java/org/thingsboard/server/dao/oauth2/deprecated/OAuth2ClientRegistrationInfoDao.java

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.oauth2;
package org.thingsboard.server.dao.oauth2.deprecated;
import org.thingsboard.server.common.data.oauth2.ExtendedOAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.ExtendedOAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.dao.Dao;
import java.util.List;
import java.util.Set;
@Deprecated
public interface OAuth2ClientRegistrationInfoDao extends Dao<OAuth2ClientRegistrationInfo> {
List<OAuth2ClientRegistrationInfo> findAll();

52
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2DomainDao.java

@ -0,0 +1,52 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
import lombok.RequiredArgsConstructor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.oauth2.OAuth2Domain;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.OAuth2DomainEntity;
import org.thingsboard.server.dao.oauth2.OAuth2DomainDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import java.util.List;
import java.util.UUID;
@Component
@RequiredArgsConstructor
public class JpaOAuth2DomainDao extends JpaAbstractDao<OAuth2DomainEntity, OAuth2Domain> implements OAuth2DomainDao {
private final OAuth2DomainRepository repository;
@Override
protected Class<OAuth2DomainEntity> getEntityClass() {
return OAuth2DomainEntity.class;
}
@Override
protected CrudRepository<OAuth2DomainEntity, UUID> getCrudRepository() {
return repository;
}
@Override
public List<OAuth2Domain> findByOAuth2ParamsId(UUID oauth2ParamsId) {
return DaoUtil.convertDataList(repository.findByOauth2ParamsId(oauth2ParamsId));
}
}

52
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2MobileDao.java

@ -0,0 +1,52 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
import lombok.RequiredArgsConstructor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.oauth2.OAuth2Mobile;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.OAuth2MobileEntity;
import org.thingsboard.server.dao.oauth2.OAuth2MobileDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import java.util.List;
import java.util.UUID;
@Component
@RequiredArgsConstructor
public class JpaOAuth2MobileDao extends JpaAbstractDao<OAuth2MobileEntity, OAuth2Mobile> implements OAuth2MobileDao {
private final OAuth2MobileRepository repository;
@Override
protected Class<OAuth2MobileEntity> getEntityClass() {
return OAuth2MobileEntity.class;
}
@Override
protected CrudRepository<OAuth2MobileEntity, UUID> getCrudRepository() {
return repository;
}
@Override
public List<OAuth2Mobile> findByOAuth2ParamsId(UUID oauth2ParamsId) {
return DaoUtil.convertDataList(repository.findByOauth2ParamsId(oauth2ParamsId));
}
}

47
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ParamsDao.java

@ -0,0 +1,47 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
import lombok.RequiredArgsConstructor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.oauth2.OAuth2Params;
import org.thingsboard.server.dao.model.sql.OAuth2ParamsEntity;
import org.thingsboard.server.dao.oauth2.OAuth2ParamsDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import java.util.UUID;
@Component
@RequiredArgsConstructor
public class JpaOAuth2ParamsDao extends JpaAbstractDao<OAuth2ParamsEntity, OAuth2Params> implements OAuth2ParamsDao {
private final OAuth2ParamsRepository repository;
@Override
protected Class<OAuth2ParamsEntity> getEntityClass() {
return OAuth2ParamsEntity.class;
}
@Override
protected CrudRepository<OAuth2ParamsEntity, UUID> getCrudRepository() {
return repository;
}
@Override
public void deleteAll() {
repository.deleteAll();
}
}

64
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2RegistrationDao.java

@ -0,0 +1,64 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
import lombok.RequiredArgsConstructor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.OAuth2RegistrationEntity;
import org.thingsboard.server.dao.oauth2.OAuth2RegistrationDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import java.util.List;
import java.util.UUID;
@Component
@RequiredArgsConstructor
public class JpaOAuth2RegistrationDao extends JpaAbstractDao<OAuth2RegistrationEntity, OAuth2Registration> implements OAuth2RegistrationDao {
private final OAuth2RegistrationRepository repository;
@Override
protected Class<OAuth2RegistrationEntity> getEntityClass() {
return OAuth2RegistrationEntity.class;
}
@Override
protected CrudRepository<OAuth2RegistrationEntity, UUID> getCrudRepository() {
return repository;
}
@Override
public List<OAuth2Registration> findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(List<SchemeType> domainSchemes, String domainName, String pkgName, PlatformType platformType) {
return DaoUtil.convertDataList(repository.findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(domainSchemes, domainName, pkgName,
platformType != null ? "%" + platformType.name() + "%" : null));
}
@Override
public List<OAuth2Registration> findByOAuth2ParamsId(UUID oauth2ParamsId) {
return DaoUtil.convertDataList(repository.findByOauth2ParamsId(oauth2ParamsId));
}
@Override
public String findAppSecret(UUID id, String pkgName) {
return repository.findAppSecret(id, pkgName);
}
}

29
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2DomainRepository.java

@ -0,0 +1,29 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
import org.springframework.data.repository.CrudRepository;
import org.thingsboard.server.dao.model.sql.OAuth2DomainEntity;
import java.util.List;
import java.util.UUID;
public interface OAuth2DomainRepository extends CrudRepository<OAuth2DomainEntity, UUID> {
List<OAuth2DomainEntity> findByOauth2ParamsId(UUID oauth2ParamsId);
}

28
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2MobileRepository.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
import org.springframework.data.repository.CrudRepository;
import org.thingsboard.server.dao.model.sql.OAuth2MobileEntity;
import java.util.List;
import java.util.UUID;
public interface OAuth2MobileRepository extends CrudRepository<OAuth2MobileEntity, UUID> {
List<OAuth2MobileEntity> findByOauth2ParamsId(UUID oauth2ParamsId);
}

24
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ParamsRepository.java

@ -0,0 +1,24 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
import org.springframework.data.repository.CrudRepository;
import org.thingsboard.server.dao.model.sql.OAuth2ParamsEntity;
import java.util.UUID;
public interface OAuth2ParamsRepository extends CrudRepository<OAuth2ParamsEntity, UUID> {
}

53
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2RegistrationRepository.java

@ -0,0 +1,53 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.dao.model.sql.OAuth2RegistrationEntity;
import java.util.List;
import java.util.UUID;
public interface OAuth2RegistrationRepository extends CrudRepository<OAuth2RegistrationEntity, UUID> {
@Query("SELECT reg " +
"FROM OAuth2RegistrationEntity reg " +
"LEFT JOIN OAuth2ParamsEntity params on reg.oauth2ParamsId = params.id " +
"LEFT JOIN OAuth2DomainEntity domain on reg.oauth2ParamsId = domain.oauth2ParamsId " +
"WHERE params.enabled = true " +
"AND domain.domainName = :domainName " +
"AND domain.domainScheme IN (:domainSchemes) " +
"AND (:pkgName IS NULL OR EXISTS (SELECT mobile FROM OAuth2MobileEntity mobile WHERE mobile.oauth2ParamsId = reg.oauth2ParamsId AND mobile.pkgName = :pkgName)) " +
"AND (:platformFilter IS NULL OR reg.platforms IS NULL OR reg.platforms = '' OR reg.platforms LIKE :platformFilter)")
List<OAuth2RegistrationEntity> findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(@Param("domainSchemes") List<SchemeType> domainSchemes,
@Param("domainName") String domainName,
@Param("pkgName") String pkgName,
@Param("platformFilter") String platformFilter);
List<OAuth2RegistrationEntity> findByOauth2ParamsId(UUID oauth2ParamsId);
@Query("SELECT mobile.appSecret " +
"FROM OAuth2MobileEntity mobile " +
"LEFT JOIN OAuth2RegistrationEntity reg on mobile.oauth2ParamsId = reg.oauth2ParamsId " +
"WHERE reg.id = :registrationId " +
"AND mobile.pkgName = :pkgName")
String findAppSecret(@Param("registrationId") UUID id,
@Param("pkgName") String pkgName);
}

10
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationDao.java → dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/JpaOAuth2ClientRegistrationDao.java

@ -13,19 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
package org.thingsboard.server.dao.sql.oauth2.deprecated;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistration;
import org.thingsboard.server.dao.model.sql.OAuth2ClientRegistrationEntity;
import org.thingsboard.server.dao.oauth2.OAuth2ClientRegistrationDao;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistration;
import org.thingsboard.server.dao.model.sql.deprecated.OAuth2ClientRegistrationEntity;
import org.thingsboard.server.dao.oauth2.deprecated.OAuth2ClientRegistrationDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import java.util.UUID;
@Deprecated
@Component
@RequiredArgsConstructor
public class JpaOAuth2ClientRegistrationDao extends JpaAbstractDao<OAuth2ClientRegistrationEntity, OAuth2ClientRegistration> implements OAuth2ClientRegistrationDao {

11
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationInfoDao.java → dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/JpaOAuth2ClientRegistrationInfoDao.java

@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
package org.thingsboard.server.dao.sql.oauth2.deprecated;
import lombok.RequiredArgsConstructor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.oauth2.ExtendedOAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.ExtendedOAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistrationInfo;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.OAuth2ClientRegistrationInfoEntity;
import org.thingsboard.server.dao.oauth2.OAuth2ClientRegistrationInfoDao;
import org.thingsboard.server.dao.model.sql.deprecated.OAuth2ClientRegistrationInfoEntity;
import org.thingsboard.server.dao.oauth2.deprecated.OAuth2ClientRegistrationInfoDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import java.util.ArrayList;
@ -31,6 +31,7 @@ import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Deprecated
@Component
@RequiredArgsConstructor
public class JpaOAuth2ClientRegistrationInfoDao extends JpaAbstractDao<OAuth2ClientRegistrationInfoEntity, OAuth2ClientRegistrationInfo> implements OAuth2ClientRegistrationInfoDao {

9
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRegistrationInfoRepository.java → dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/OAuth2ClientRegistrationInfoRepository.java

@ -13,18 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
package org.thingsboard.server.dao.sql.oauth2.deprecated;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.dao.model.sql.ExtendedOAuth2ClientRegistrationInfoEntity;
import org.thingsboard.server.dao.model.sql.OAuth2ClientRegistrationInfoEntity;
import org.thingsboard.server.dao.model.sql.deprecated.ExtendedOAuth2ClientRegistrationInfoEntity;
import org.thingsboard.server.dao.model.sql.deprecated.OAuth2ClientRegistrationInfoEntity;
import java.util.List;
import java.util.UUID;
@Deprecated
public interface OAuth2ClientRegistrationInfoRepository extends CrudRepository<OAuth2ClientRegistrationInfoEntity, UUID> {
@Query("SELECT new OAuth2ClientRegistrationInfoEntity(cr_info) " +
"FROM OAuth2ClientRegistrationInfoEntity cr_info " +
@ -34,7 +35,7 @@ public interface OAuth2ClientRegistrationInfoRepository extends CrudRepository<O
List<OAuth2ClientRegistrationInfoEntity> findAllByDomainSchemesAndName(@Param("domainSchemes") List<SchemeType> domainSchemes,
@Param("domainName") String domainName);
@Query("SELECT new org.thingsboard.server.dao.model.sql.ExtendedOAuth2ClientRegistrationInfoEntity(cr_info, cr.domainName, cr.domainScheme) " +
@Query("SELECT new org.thingsboard.server.dao.model.sql.deprecated.ExtendedOAuth2ClientRegistrationInfoEntity(cr_info, cr.domainName, cr.domainScheme) " +
"FROM OAuth2ClientRegistrationInfoEntity cr_info " +
"LEFT JOIN OAuth2ClientRegistrationEntity cr on cr_info.id = cr.clientRegistrationInfoId ")
List<ExtendedOAuth2ClientRegistrationInfoEntity> findAllExtended();

5
dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRegistrationRepository.java → dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/OAuth2ClientRegistrationRepository.java

@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.oauth2;
package org.thingsboard.server.dao.sql.oauth2.deprecated;
import org.springframework.data.repository.CrudRepository;
import org.thingsboard.server.dao.model.sql.OAuth2ClientRegistrationEntity;
import org.thingsboard.server.dao.model.sql.deprecated.OAuth2ClientRegistrationEntity;
import java.util.UUID;
@Deprecated
public interface OAuth2ClientRegistrationRepository extends CrudRepository<OAuth2ClientRegistrationEntity, UUID> {
}

76
dao/src/main/resources/sql/schema-entities-hsql.sql

@ -374,9 +374,16 @@ CREATE TABLE IF NOT EXISTS ts_kv_dictionary (
CONSTRAINT ts_key_id_pkey PRIMARY KEY (key)
);
CREATE TABLE IF NOT EXISTS oauth2_client_registration_info (
id uuid NOT NULL CONSTRAINT oauth2_client_registration_info_pkey PRIMARY KEY,
CREATE TABLE IF NOT EXISTS oauth2_params (
id uuid NOT NULL CONSTRAINT oauth2_params_pkey PRIMARY KEY,
enabled boolean,
tenant_id uuid,
created_time bigint NOT NULL
);
CREATE TABLE IF NOT EXISTS oauth2_registration (
id uuid NOT NULL CONSTRAINT oauth2_registration_pkey PRIMARY KEY,
oauth2_params_id uuid NOT NULL,
created_time bigint NOT NULL,
additional_info varchar,
client_id varchar(255),
@ -384,6 +391,7 @@ CREATE TABLE IF NOT EXISTS oauth2_client_registration_info (
authorization_uri varchar(255),
token_uri varchar(255),
scope varchar(255),
platforms varchar(255),
user_info_uri varchar(255),
user_name_attribute_name varchar(255),
jwk_set_uri varchar(255),
@ -404,15 +412,28 @@ CREATE TABLE IF NOT EXISTS oauth2_client_registration_info (
custom_url varchar(255),
custom_username varchar(255),
custom_password varchar(255),
custom_send_token boolean
custom_send_token boolean,
CONSTRAINT fk_registration_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS oauth2_client_registration (
id uuid NOT NULL CONSTRAINT oauth2_client_registration_pkey PRIMARY KEY,
CREATE TABLE IF NOT EXISTS oauth2_domain (
id uuid NOT NULL CONSTRAINT oauth2_domain_pkey PRIMARY KEY,
oauth2_params_id uuid NOT NULL,
created_time bigint NOT NULL,
domain_name varchar(255),
domain_scheme varchar(31),
client_registration_info_id uuid
CONSTRAINT fk_domain_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE,
CONSTRAINT oauth2_domain_unq_key UNIQUE (oauth2_params_id, domain_name, domain_scheme)
);
CREATE TABLE IF NOT EXISTS oauth2_mobile (
id uuid NOT NULL CONSTRAINT oauth2_mobile_pkey PRIMARY KEY,
oauth2_params_id uuid NOT NULL,
created_time bigint NOT NULL,
pkg_name varchar(255),
app_secret varchar(2048),
CONSTRAINT fk_mobile_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE,
CONSTRAINT oauth2_mobile_unq_key UNIQUE (oauth2_params_id, pkg_name)
);
CREATE TABLE IF NOT EXISTS oauth2_client_registration_template (
@ -443,6 +464,49 @@ CREATE TABLE IF NOT EXISTS oauth2_client_registration_template (
CONSTRAINT oauth2_template_provider_id_unq_key UNIQUE (provider_id)
);
-- Deprecated
CREATE TABLE IF NOT EXISTS oauth2_client_registration_info (
id uuid NOT NULL CONSTRAINT oauth2_client_registration_info_pkey PRIMARY KEY,
enabled boolean,
created_time bigint NOT NULL,
additional_info varchar,
client_id varchar(255),
client_secret varchar(255),
authorization_uri varchar(255),
token_uri varchar(255),
scope varchar(255),
user_info_uri varchar(255),
user_name_attribute_name varchar(255),
jwk_set_uri varchar(255),
client_authentication_method varchar(255),
login_button_label varchar(255),
login_button_icon varchar(255),
allow_user_creation boolean,
activate_user boolean,
type varchar(31),
basic_email_attribute_key varchar(31),
basic_first_name_attribute_key varchar(31),
basic_last_name_attribute_key varchar(31),
basic_tenant_name_strategy varchar(31),
basic_tenant_name_pattern varchar(255),
basic_customer_name_pattern varchar(255),
basic_default_dashboard_name varchar(255),
basic_always_full_screen boolean,
custom_url varchar(255),
custom_username varchar(255),
custom_password varchar(255),
custom_send_token boolean
);
-- Deprecated
CREATE TABLE IF NOT EXISTS oauth2_client_registration (
id uuid NOT NULL CONSTRAINT oauth2_client_registration_pkey PRIMARY KEY,
created_time bigint NOT NULL,
domain_name varchar(255),
domain_scheme varchar(31),
client_registration_info_id uuid
);
CREATE TABLE IF NOT EXISTS api_usage_state (
id uuid NOT NULL CONSTRAINT usage_record_pkey PRIMARY KEY,
created_time bigint NOT NULL,

76
dao/src/main/resources/sql/schema-entities.sql

@ -411,9 +411,16 @@ CREATE TABLE IF NOT EXISTS ts_kv_dictionary
CONSTRAINT ts_key_id_pkey PRIMARY KEY (key)
);
CREATE TABLE IF NOT EXISTS oauth2_client_registration_info (
id uuid NOT NULL CONSTRAINT oauth2_client_registration_info_pkey PRIMARY KEY,
CREATE TABLE IF NOT EXISTS oauth2_params (
id uuid NOT NULL CONSTRAINT oauth2_params_pkey PRIMARY KEY,
enabled boolean,
tenant_id uuid,
created_time bigint NOT NULL
);
CREATE TABLE IF NOT EXISTS oauth2_registration (
id uuid NOT NULL CONSTRAINT oauth2_registration_pkey PRIMARY KEY,
oauth2_params_id uuid NOT NULL,
created_time bigint NOT NULL,
additional_info varchar,
client_id varchar(255),
@ -421,6 +428,7 @@ CREATE TABLE IF NOT EXISTS oauth2_client_registration_info (
authorization_uri varchar(255),
token_uri varchar(255),
scope varchar(255),
platforms varchar(255),
user_info_uri varchar(255),
user_name_attribute_name varchar(255),
jwk_set_uri varchar(255),
@ -441,15 +449,28 @@ CREATE TABLE IF NOT EXISTS oauth2_client_registration_info (
custom_url varchar(255),
custom_username varchar(255),
custom_password varchar(255),
custom_send_token boolean
custom_send_token boolean,
CONSTRAINT fk_registration_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS oauth2_client_registration (
id uuid NOT NULL CONSTRAINT oauth2_client_registration_pkey PRIMARY KEY,
CREATE TABLE IF NOT EXISTS oauth2_domain (
id uuid NOT NULL CONSTRAINT oauth2_domain_pkey PRIMARY KEY,
oauth2_params_id uuid NOT NULL,
created_time bigint NOT NULL,
domain_name varchar(255),
domain_scheme varchar(31),
client_registration_info_id uuid
CONSTRAINT fk_domain_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE,
CONSTRAINT oauth2_domain_unq_key UNIQUE (oauth2_params_id, domain_name, domain_scheme)
);
CREATE TABLE IF NOT EXISTS oauth2_mobile (
id uuid NOT NULL CONSTRAINT oauth2_mobile_pkey PRIMARY KEY,
oauth2_params_id uuid NOT NULL,
created_time bigint NOT NULL,
pkg_name varchar(255),
app_secret varchar(2048),
CONSTRAINT fk_mobile_oauth2_params FOREIGN KEY (oauth2_params_id) REFERENCES oauth2_params(id) ON DELETE CASCADE,
CONSTRAINT oauth2_mobile_unq_key UNIQUE (oauth2_params_id, pkg_name)
);
CREATE TABLE IF NOT EXISTS oauth2_client_registration_template (
@ -480,6 +501,49 @@ CREATE TABLE IF NOT EXISTS oauth2_client_registration_template (
CONSTRAINT oauth2_template_provider_id_unq_key UNIQUE (provider_id)
);
-- Deprecated
CREATE TABLE IF NOT EXISTS oauth2_client_registration_info (
id uuid NOT NULL CONSTRAINT oauth2_client_registration_info_pkey PRIMARY KEY,
enabled boolean,
created_time bigint NOT NULL,
additional_info varchar,
client_id varchar(255),
client_secret varchar(255),
authorization_uri varchar(255),
token_uri varchar(255),
scope varchar(255),
user_info_uri varchar(255),
user_name_attribute_name varchar(255),
jwk_set_uri varchar(255),
client_authentication_method varchar(255),
login_button_label varchar(255),
login_button_icon varchar(255),
allow_user_creation boolean,
activate_user boolean,
type varchar(31),
basic_email_attribute_key varchar(31),
basic_first_name_attribute_key varchar(31),
basic_last_name_attribute_key varchar(31),
basic_tenant_name_strategy varchar(31),
basic_tenant_name_pattern varchar(255),
basic_customer_name_pattern varchar(255),
basic_default_dashboard_name varchar(255),
basic_always_full_screen boolean,
custom_url varchar(255),
custom_username varchar(255),
custom_password varchar(255),
custom_send_token boolean
);
-- Deprecated
CREATE TABLE IF NOT EXISTS oauth2_client_registration (
id uuid NOT NULL CONSTRAINT oauth2_client_registration_pkey PRIMARY KEY,
created_time bigint NOT NULL,
domain_name varchar(255),
domain_scheme varchar(31),
client_registration_info_id uuid
);
CREATE TABLE IF NOT EXISTS api_usage_state (
id uuid NOT NULL CONSTRAINT usage_record_pkey PRIMARY KEY,
created_time bigint NOT NULL,

551
dao/src/test/java/org/thingsboard/server/dao/service/BaseOAuth2ServiceTest.java

@ -16,208 +16,227 @@
package org.thingsboard.server.dao.service;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.oauth2.*;
import org.thingsboard.server.common.data.oauth2.MapperType;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2CustomMapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2DomainInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
import org.thingsboard.server.common.data.oauth2.OAuth2MobileInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2ParamsInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.common.data.oauth2.OAuth2RegistrationInfo;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.oauth2.SchemeType;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.oauth2.OAuth2Service;
import java.util.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class BaseOAuth2ServiceTest extends AbstractServiceTest {
private static final OAuth2ClientsParams EMPTY_PARAMS = new OAuth2ClientsParams(false, new ArrayList<>());
private static final OAuth2Info EMPTY_PARAMS = new OAuth2Info(false, Collections.emptyList());
@Autowired
protected OAuth2Service oAuth2Service;
@Before
public void beforeRun() {
Assert.assertTrue(oAuth2Service.findAllClientRegistrationInfos().isEmpty());
Assert.assertTrue(oAuth2Service.findAllRegistrations().isEmpty());
}
@After
public void after() {
oAuth2Service.saveOAuth2Params(EMPTY_PARAMS);
Assert.assertTrue(oAuth2Service.findAllClientRegistrationInfos().isEmpty());
Assert.assertTrue(oAuth2Service.findOAuth2Params().getDomainsParams().isEmpty());
oAuth2Service.saveOAuth2Info(EMPTY_PARAMS);
Assert.assertTrue(oAuth2Service.findAllRegistrations().isEmpty());
Assert.assertTrue(oAuth2Service.findOAuth2Info().getOauth2ParamsInfos().isEmpty());
}
@Test(expected = DataValidationException.class)
public void testSaveHttpAndMixedDomainsTogether() {
OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList(
OAuth2ClientsDomainParams.builder()
OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("first-domain").scheme(SchemeType.MIXED).build(),
DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto()
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo()
))
.build()
));
oAuth2Service.saveOAuth2Params(clientsParams);
oAuth2Service.saveOAuth2Info(oAuth2Info);
}
@Test(expected = DataValidationException.class)
public void testSaveHttpsAndMixedDomainsTogether() {
OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList(
OAuth2ClientsDomainParams.builder()
OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTPS).build(),
DomainInfo.builder().name("first-domain").scheme(SchemeType.MIXED).build(),
DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTPS).build(),
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto()
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo()
))
.build()
));
oAuth2Service.saveOAuth2Params(clientsParams);
oAuth2Service.saveOAuth2Info(oAuth2Info);
}
@Test
public void testCreateAndFindParams() {
OAuth2ClientsParams clientsParams = createDefaultClientsParams();
oAuth2Service.saveOAuth2Params(clientsParams);
OAuth2ClientsParams foundClientsParams = oAuth2Service.findOAuth2Params();
Assert.assertNotNull(foundClientsParams);
OAuth2Info oAuth2Info = createDefaultOAuth2Info();
oAuth2Service.saveOAuth2Info(oAuth2Info);
OAuth2Info foundOAuth2Info = oAuth2Service.findOAuth2Info();
Assert.assertNotNull(foundOAuth2Info);
// TODO ask if it's safe to check equality on AdditionalProperties
Assert.assertEquals(clientsParams, foundClientsParams);
Assert.assertEquals(oAuth2Info, foundOAuth2Info);
}
@Test
public void testDisableParams() {
OAuth2ClientsParams clientsParams = createDefaultClientsParams();
clientsParams.setEnabled(true);
oAuth2Service.saveOAuth2Params(clientsParams);
OAuth2ClientsParams foundClientsParams = oAuth2Service.findOAuth2Params();
Assert.assertNotNull(foundClientsParams);
Assert.assertEquals(clientsParams, foundClientsParams);
clientsParams.setEnabled(false);
oAuth2Service.saveOAuth2Params(clientsParams);
OAuth2ClientsParams foundDisabledClientsParams = oAuth2Service.findOAuth2Params();
Assert.assertEquals(clientsParams, foundDisabledClientsParams);
OAuth2Info oAuth2Info = createDefaultOAuth2Info();
oAuth2Info.setEnabled(true);
oAuth2Service.saveOAuth2Info(oAuth2Info);
OAuth2Info foundOAuth2Info = oAuth2Service.findOAuth2Info();
Assert.assertNotNull(foundOAuth2Info);
Assert.assertEquals(oAuth2Info, foundOAuth2Info);
oAuth2Info.setEnabled(false);
oAuth2Service.saveOAuth2Info(oAuth2Info);
OAuth2Info foundDisabledOAuth2Info = oAuth2Service.findOAuth2Info();
Assert.assertEquals(oAuth2Info, foundDisabledOAuth2Info);
}
@Test
public void testClearDomainParams() {
OAuth2ClientsParams clientsParams = createDefaultClientsParams();
oAuth2Service.saveOAuth2Params(clientsParams);
OAuth2ClientsParams foundClientsParams = oAuth2Service.findOAuth2Params();
Assert.assertNotNull(foundClientsParams);
Assert.assertEquals(clientsParams, foundClientsParams);
oAuth2Service.saveOAuth2Params(EMPTY_PARAMS);
OAuth2ClientsParams foundAfterClearClientsParams = oAuth2Service.findOAuth2Params();
OAuth2Info oAuth2Info = createDefaultOAuth2Info();
oAuth2Service.saveOAuth2Info(oAuth2Info);
OAuth2Info foundOAuth2Info = oAuth2Service.findOAuth2Info();
Assert.assertNotNull(foundOAuth2Info);
Assert.assertEquals(oAuth2Info, foundOAuth2Info);
oAuth2Service.saveOAuth2Info(EMPTY_PARAMS);
OAuth2Info foundAfterClearClientsParams = oAuth2Service.findOAuth2Info();
Assert.assertNotNull(foundAfterClearClientsParams);
Assert.assertEquals(EMPTY_PARAMS, foundAfterClearClientsParams);
}
@Test
public void testUpdateClientsParams() {
OAuth2ClientsParams clientsParams = createDefaultClientsParams();
oAuth2Service.saveOAuth2Params(clientsParams);
OAuth2ClientsParams foundClientsParams = oAuth2Service.findOAuth2Params();
Assert.assertNotNull(foundClientsParams);
Assert.assertEquals(clientsParams, foundClientsParams);
OAuth2ClientsParams newClientsParams = new OAuth2ClientsParams(true, Lists.newArrayList(
OAuth2ClientsDomainParams.builder()
OAuth2Info oAuth2Info = createDefaultOAuth2Info();
oAuth2Service.saveOAuth2Info(oAuth2Info);
OAuth2Info foundOAuth2Info = oAuth2Service.findOAuth2Info();
Assert.assertNotNull(foundOAuth2Info);
Assert.assertEquals(oAuth2Info, foundOAuth2Info);
OAuth2Info newOAuth2Info = new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("another-domain").scheme(SchemeType.HTTPS).build()
OAuth2DomainInfo.builder().name("another-domain").scheme(SchemeType.HTTPS).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto()
validRegistrationInfo()
))
.build(),
OAuth2ClientsDomainParams.builder()
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("test-domain").scheme(SchemeType.MIXED).build()
OAuth2DomainInfo.builder().name("test-domain").scheme(SchemeType.MIXED).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto()
validRegistrationInfo()
))
.build()
));
oAuth2Service.saveOAuth2Params(newClientsParams);
OAuth2ClientsParams foundAfterUpdateClientsParams = oAuth2Service.findOAuth2Params();
Assert.assertNotNull(foundAfterUpdateClientsParams);
Assert.assertEquals(newClientsParams, foundAfterUpdateClientsParams);
oAuth2Service.saveOAuth2Info(newOAuth2Info);
OAuth2Info foundAfterUpdateOAuth2Info = oAuth2Service.findOAuth2Info();
Assert.assertNotNull(foundAfterUpdateOAuth2Info);
Assert.assertEquals(newOAuth2Info, foundAfterUpdateOAuth2Info);
}
@Test
public void testGetOAuth2Clients() {
List<ClientRegistrationDto> firstGroup = Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto()
List<OAuth2RegistrationInfo> firstGroup = Lists.newArrayList(
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo()
);
List<ClientRegistrationDto> secondGroup = Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto()
List<OAuth2RegistrationInfo> secondGroup = Lists.newArrayList(
validRegistrationInfo(),
validRegistrationInfo()
);
List<ClientRegistrationDto> thirdGroup = Lists.newArrayList(
validClientRegistrationDto()
List<OAuth2RegistrationInfo> thirdGroup = Lists.newArrayList(
validRegistrationInfo()
);
OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList(
OAuth2ClientsDomainParams.builder()
OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(firstGroup)
.build(),
OAuth2ClientsDomainParams.builder()
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(secondGroup)
.build(),
OAuth2ClientsDomainParams.builder()
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(),
DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build()
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(),
OAuth2DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(thirdGroup)
.build()
));
oAuth2Service.saveOAuth2Params(clientsParams);
OAuth2ClientsParams foundClientsParams = oAuth2Service.findOAuth2Params();
Assert.assertNotNull(foundClientsParams);
Assert.assertEquals(clientsParams, foundClientsParams);
oAuth2Service.saveOAuth2Info(oAuth2Info);
OAuth2Info foundOAuth2Info = oAuth2Service.findOAuth2Info();
Assert.assertNotNull(foundOAuth2Info);
Assert.assertEquals(oAuth2Info, foundOAuth2Info);
List<OAuth2ClientInfo> firstGroupClientInfos = firstGroup.stream()
.map(clientRegistrationDto -> new OAuth2ClientInfo(
clientRegistrationDto.getLoginButtonLabel(), clientRegistrationDto.getLoginButtonIcon(), null))
.map(registrationInfo -> new OAuth2ClientInfo(
registrationInfo.getLoginButtonLabel(), registrationInfo.getLoginButtonIcon(), null))
.collect(Collectors.toList());
List<OAuth2ClientInfo> secondGroupClientInfos = secondGroup.stream()
.map(clientRegistrationDto -> new OAuth2ClientInfo(
clientRegistrationDto.getLoginButtonLabel(), clientRegistrationDto.getLoginButtonIcon(), null))
.map(registrationInfo -> new OAuth2ClientInfo(
registrationInfo.getLoginButtonLabel(), registrationInfo.getLoginButtonIcon(), null))
.collect(Collectors.toList());
List<OAuth2ClientInfo> thirdGroupClientInfos = thirdGroup.stream()
.map(clientRegistrationDto -> new OAuth2ClientInfo(
clientRegistrationDto.getLoginButtonLabel(), clientRegistrationDto.getLoginButtonIcon(), null))
.map(registrationInfo -> new OAuth2ClientInfo(
registrationInfo.getLoginButtonLabel(), registrationInfo.getLoginButtonIcon(), null))
.collect(Collectors.toList());
List<OAuth2ClientInfo> nonExistentDomainClients = oAuth2Service.getOAuth2Clients("http", "non-existent-domain");
List<OAuth2ClientInfo> nonExistentDomainClients = oAuth2Service.getOAuth2Clients("http", "non-existent-domain", null, null);
Assert.assertTrue(nonExistentDomainClients.isEmpty());
List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain");
List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", null, null);
Assert.assertEquals(firstGroupClientInfos.size(), firstDomainHttpClients.size());
firstGroupClientInfos.forEach(firstGroupClientInfo -> {
Assert.assertTrue(
@ -227,10 +246,10 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
);
});
List<OAuth2ClientInfo> firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain");
List<OAuth2ClientInfo> firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain", null, null);
Assert.assertTrue(firstDomainHttpsClients.isEmpty());
List<OAuth2ClientInfo> fourthDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "fourth-domain");
List<OAuth2ClientInfo> fourthDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "fourth-domain", null, null);
Assert.assertEquals(secondGroupClientInfos.size(), fourthDomainHttpClients.size());
secondGroupClientInfos.forEach(secondGroupClientInfo -> {
Assert.assertTrue(
@ -239,7 +258,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
&& clientInfo.getName().equals(secondGroupClientInfo.getName()))
);
});
List<OAuth2ClientInfo> fourthDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "fourth-domain");
List<OAuth2ClientInfo> fourthDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "fourth-domain", null, null);
Assert.assertEquals(secondGroupClientInfos.size(), fourthDomainHttpsClients.size());
secondGroupClientInfos.forEach(secondGroupClientInfo -> {
Assert.assertTrue(
@ -249,7 +268,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
);
});
List<OAuth2ClientInfo> secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain");
List<OAuth2ClientInfo> secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null, null);
Assert.assertEquals(firstGroupClientInfos.size() + secondGroupClientInfos.size(), secondDomainHttpClients.size());
firstGroupClientInfos.forEach(firstGroupClientInfo -> {
Assert.assertTrue(
@ -266,7 +285,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
);
});
List<OAuth2ClientInfo> secondDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "second-domain");
List<OAuth2ClientInfo> secondDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "second-domain", null, null);
Assert.assertEquals(firstGroupClientInfos.size() + thirdGroupClientInfos.size(), secondDomainHttpsClients.size());
firstGroupClientInfos.forEach(firstGroupClientInfo -> {
Assert.assertTrue(
@ -286,34 +305,35 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
@Test
public void testGetOAuth2ClientsForHttpAndHttps() {
List<ClientRegistrationDto> firstGroup = Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto()
List<OAuth2RegistrationInfo> firstGroup = Lists.newArrayList(
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo()
);
OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList(
OAuth2ClientsDomainParams.builder()
OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTPS).build()
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTPS).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(firstGroup)
.build()
));
oAuth2Service.saveOAuth2Params(clientsParams);
OAuth2ClientsParams foundClientsParams = oAuth2Service.findOAuth2Params();
Assert.assertNotNull(foundClientsParams);
Assert.assertEquals(clientsParams, foundClientsParams);
oAuth2Service.saveOAuth2Info(oAuth2Info);
OAuth2Info foundOAuth2Info = oAuth2Service.findOAuth2Info();
Assert.assertNotNull(foundOAuth2Info);
Assert.assertEquals(oAuth2Info, foundOAuth2Info);
List<OAuth2ClientInfo> firstGroupClientInfos = firstGroup.stream()
.map(clientRegistrationDto -> new OAuth2ClientInfo(
clientRegistrationDto.getLoginButtonLabel(), clientRegistrationDto.getLoginButtonIcon(), null))
.map(registrationInfo -> new OAuth2ClientInfo(
registrationInfo.getLoginButtonLabel(), registrationInfo.getLoginButtonIcon(), null))
.collect(Collectors.toList());
List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain");
List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", null, null);
Assert.assertEquals(firstGroupClientInfos.size(), firstDomainHttpClients.size());
firstGroupClientInfos.forEach(firstGroupClientInfo -> {
Assert.assertTrue(
@ -323,7 +343,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
);
});
List<OAuth2ClientInfo> firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain");
List<OAuth2ClientInfo> firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain", null, null);
Assert.assertEquals(firstGroupClientInfos.size(), firstDomainHttpsClients.size());
firstGroupClientInfos.forEach(firstGroupClientInfo -> {
Assert.assertTrue(
@ -336,176 +356,285 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
@Test
public void testGetDisabledOAuth2Clients() {
OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList(
OAuth2ClientsDomainParams.builder()
OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto()
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo()
))
.build(),
OAuth2ClientsDomainParams.builder()
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto()
validRegistrationInfo(),
validRegistrationInfo()
))
.build()
));
oAuth2Service.saveOAuth2Params(clientsParams);
oAuth2Service.saveOAuth2Info(oAuth2Info);
List<OAuth2ClientInfo> secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain");
List<OAuth2ClientInfo> secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null, null);
Assert.assertEquals(5, secondDomainHttpClients.size());
clientsParams.setEnabled(false);
oAuth2Service.saveOAuth2Params(clientsParams);
oAuth2Info.setEnabled(false);
oAuth2Service.saveOAuth2Info(oAuth2Info);
List<OAuth2ClientInfo> secondDomainHttpDisabledClients = oAuth2Service.getOAuth2Clients("http", "second-domain");
List<OAuth2ClientInfo> secondDomainHttpDisabledClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null, null);
Assert.assertEquals(0, secondDomainHttpDisabledClients.size());
}
@Test
public void testFindAllClientRegistrationInfos() {
OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList(
OAuth2ClientsDomainParams.builder()
public void testFindAllRegistrations() {
OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto()
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo()
))
.build(),
OAuth2ClientsDomainParams.builder()
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto()
validRegistrationInfo(),
validRegistrationInfo()
))
.build(),
OAuth2ClientsDomainParams.builder()
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(),
DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build()
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(),
OAuth2DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build()
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto()
validRegistrationInfo()
))
.build()
));
oAuth2Service.saveOAuth2Params(clientsParams);
List<OAuth2ClientRegistrationInfo> foundClientRegistrationInfos = oAuth2Service.findAllClientRegistrationInfos();
Assert.assertEquals(6, foundClientRegistrationInfos.size());
clientsParams.getDomainsParams().stream()
.flatMap(domainParams -> domainParams.getClientRegistrations().stream())
.forEach(clientRegistrationDto ->
oAuth2Service.saveOAuth2Info(oAuth2Info);
List<OAuth2Registration> foundRegistrations = oAuth2Service.findAllRegistrations();
Assert.assertEquals(6, foundRegistrations.size());
oAuth2Info.getOauth2ParamsInfos().stream()
.flatMap(paramsInfo -> paramsInfo.getClientRegistrations().stream())
.forEach(registrationInfo ->
Assert.assertTrue(
foundClientRegistrationInfos.stream()
.anyMatch(clientRegistrationInfo -> clientRegistrationInfo.getClientId().equals(clientRegistrationDto.getClientId()))
foundRegistrations.stream()
.anyMatch(registration -> registration.getClientId().equals(registrationInfo.getClientId()))
)
);
}
@Test
public void testFindClientRegistrationById() {
OAuth2ClientsParams clientsParams = new OAuth2ClientsParams(true, Lists.newArrayList(
OAuth2ClientsDomainParams.builder()
public void testFindRegistrationById() {
OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto()
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo()
))
.build(),
OAuth2ClientsDomainParams.builder()
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto()
validRegistrationInfo(),
validRegistrationInfo()
))
.build(),
OAuth2ClientsDomainParams.builder()
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(),
DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build()
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTPS).build(),
OAuth2DomainInfo.builder().name("fifth-domain").scheme(SchemeType.HTTP).build()
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto()
validRegistrationInfo()
))
.build()
));
oAuth2Service.saveOAuth2Params(clientsParams);
List<OAuth2ClientRegistrationInfo> clientRegistrationInfos = oAuth2Service.findAllClientRegistrationInfos();
clientRegistrationInfos.forEach(clientRegistrationInfo -> {
OAuth2ClientRegistrationInfo foundClientRegistrationInfo = oAuth2Service.findClientRegistrationInfo(clientRegistrationInfo.getUuidId());
Assert.assertEquals(clientRegistrationInfo, foundClientRegistrationInfo);
oAuth2Service.saveOAuth2Info(oAuth2Info);
List<OAuth2Registration> foundRegistrations = oAuth2Service.findAllRegistrations();
foundRegistrations.forEach(registration -> {
OAuth2Registration foundRegistration = oAuth2Service.findRegistration(registration.getUuidId());
Assert.assertEquals(registration, foundRegistration);
});
}
private OAuth2ClientsParams createDefaultClientsParams() {
return new OAuth2ClientsParams(true, Lists.newArrayList(
OAuth2ClientsDomainParams.builder()
@Test
public void testFindAppSecret() {
OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
))
.mobileInfos(Lists.newArrayList(
validMobileInfo("com.test.pkg1", "testPkg1AppSecret"),
validMobileInfo("com.test.pkg2", "testPkg2AppSecret")
))
.clientRegistrations(Lists.newArrayList(
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo()
))
.build(),
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(Lists.newArrayList(
validRegistrationInfo(),
validRegistrationInfo()
))
.build()
));
oAuth2Service.saveOAuth2Info(oAuth2Info);
OAuth2Info foundOAuth2Info = oAuth2Service.findOAuth2Info();
Assert.assertEquals(oAuth2Info, foundOAuth2Info);
List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", "com.test.pkg1", null);
Assert.assertEquals(3, firstDomainHttpClients.size());
for (OAuth2ClientInfo clientInfo : firstDomainHttpClients) {
String[] segments = clientInfo.getUrl().split("/");
String registrationId = segments[segments.length-1];
String appSecret = oAuth2Service.findAppSecret(UUID.fromString(registrationId), "com.test.pkg1");
Assert.assertNotNull(appSecret);
Assert.assertEquals("testPkg1AppSecret", appSecret);
appSecret = oAuth2Service.findAppSecret(UUID.fromString(registrationId), "com.test.pkg2");
Assert.assertNotNull(appSecret);
Assert.assertEquals("testPkg2AppSecret", appSecret);
appSecret = oAuth2Service.findAppSecret(UUID.fromString(registrationId), "com.test.pkg3");
Assert.assertNull(appSecret);
}
}
@Test
public void testFindClientsByPackageAndPlatform() {
OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
))
.mobileInfos(Lists.newArrayList(
validMobileInfo("com.test.pkg1", "testPkg1Callback"),
validMobileInfo("com.test.pkg2", "testPkg2Callback")
))
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto(),
validClientRegistrationDto()
validRegistrationInfo("Google", Arrays.asList(PlatformType.WEB, PlatformType.ANDROID)),
validRegistrationInfo("Facebook", Arrays.asList(PlatformType.IOS)),
validRegistrationInfo("GitHub", Collections.emptyList())
))
.build(),
OAuth2ClientsDomainParams.builder()
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(Lists.newArrayList(
validClientRegistrationDto(),
validClientRegistrationDto()
validRegistrationInfo(),
validRegistrationInfo()
))
.build()
));
oAuth2Service.saveOAuth2Info(oAuth2Info);
OAuth2Info foundOAuth2Info = oAuth2Service.findOAuth2Info();
Assert.assertEquals(oAuth2Info, foundOAuth2Info);
List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", null, null);
Assert.assertEquals(3, firstDomainHttpClients.size());
List<OAuth2ClientInfo> pkg1Clients = oAuth2Service.getOAuth2Clients("http", "first-domain", "com.test.pkg1", null);
Assert.assertEquals(3, pkg1Clients.size());
List<OAuth2ClientInfo> pkg1AndroidClients = oAuth2Service.getOAuth2Clients("http", "first-domain", "com.test.pkg1", PlatformType.ANDROID);
Assert.assertEquals(2, pkg1AndroidClients.size());
Assert.assertTrue(pkg1AndroidClients.stream().anyMatch(client -> client.getName().equals("Google")));
Assert.assertTrue(pkg1AndroidClients.stream().anyMatch(client -> client.getName().equals("GitHub")));
List<OAuth2ClientInfo> pkg1IOSClients = oAuth2Service.getOAuth2Clients("http", "first-domain", "com.test.pkg1", PlatformType.IOS);
Assert.assertEquals(2, pkg1IOSClients.size());
Assert.assertTrue(pkg1IOSClients.stream().anyMatch(client -> client.getName().equals("Facebook")));
Assert.assertTrue(pkg1IOSClients.stream().anyMatch(client -> client.getName().equals("GitHub")));
}
private ClientRegistrationDto validClientRegistrationDto() {
return ClientRegistrationDto.builder()
private OAuth2Info createDefaultOAuth2Info() {
return new OAuth2Info(true, Lists.newArrayList(
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(Lists.newArrayList(
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo(),
validRegistrationInfo()
))
.build(),
OAuth2ParamsInfo.builder()
.domainInfos(Lists.newArrayList(
OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
OAuth2DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
))
.mobileInfos(Collections.emptyList())
.clientRegistrations(Lists.newArrayList(
validRegistrationInfo(),
validRegistrationInfo()
))
.build()
));
}
private OAuth2RegistrationInfo validRegistrationInfo() {
return validRegistrationInfo(null, Collections.emptyList());
}
private OAuth2RegistrationInfo validRegistrationInfo(String label, List<PlatformType> platforms) {
return OAuth2RegistrationInfo.builder()
.clientId(UUID.randomUUID().toString())
.clientSecret(UUID.randomUUID().toString())
.authorizationUri(UUID.randomUUID().toString())
.accessTokenUri(UUID.randomUUID().toString())
.scope(Arrays.asList(UUID.randomUUID().toString(), UUID.randomUUID().toString()))
.platforms(platforms == null ? Collections.emptyList() : platforms)
.userInfoUri(UUID.randomUUID().toString())
.userNameAttributeName(UUID.randomUUID().toString())
.jwkSetUri(UUID.randomUUID().toString())
.clientAuthenticationMethod(UUID.randomUUID().toString())
.loginButtonLabel(UUID.randomUUID().toString())
.loginButtonLabel(label != null ? label : UUID.randomUUID().toString())
.loginButtonIcon(UUID.randomUUID().toString())
.additionalInfo(mapper.createObjectNode().put(UUID.randomUUID().toString(), UUID.randomUUID().toString()))
.mapperConfig(
@ -522,4 +651,10 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
)
.build();
}
private OAuth2MobileInfo validMobileInfo(String pkgName, String appSecret) {
return OAuth2MobileInfo.builder().pkgName(pkgName)
.appSecret(appSecret != null ? appSecret : RandomStringUtils.randomAlphanumeric(24))
.build();
}
}

6
dao/src/test/resources/sql/hsql/drop-all-tables.sql

@ -24,9 +24,13 @@ DROP TABLE IF EXISTS dashboard;
DROP TABLE IF EXISTS rule_node_state;
DROP TABLE IF EXISTS rule_node;
DROP TABLE IF EXISTS rule_chain;
DROP TABLE IF EXISTS oauth2_mobile;
DROP TABLE IF EXISTS oauth2_domain;
DROP TABLE IF EXISTS oauth2_registration;
DROP TABLE IF EXISTS oauth2_params;
DROP TABLE IF EXISTS oauth2_client_registration_template;
DROP TABLE IF EXISTS oauth2_client_registration;
DROP TABLE IF EXISTS oauth2_client_registration_info;
DROP TABLE IF EXISTS oauth2_client_registration_template;
DROP TABLE IF EXISTS api_usage_state;
DROP TABLE IF EXISTS resource;
DROP TABLE IF EXISTS ota_package;

6
dao/src/test/resources/sql/psql/drop-all-tables.sql

@ -25,9 +25,13 @@ DROP TABLE IF EXISTS rule_node_state;
DROP TABLE IF EXISTS rule_node;
DROP TABLE IF EXISTS rule_chain;
DROP TABLE IF EXISTS tb_schema_settings;
DROP TABLE IF EXISTS oauth2_mobile;
DROP TABLE IF EXISTS oauth2_domain;
DROP TABLE IF EXISTS oauth2_registration;
DROP TABLE IF EXISTS oauth2_params;
DROP TABLE IF EXISTS oauth2_client_registration_template;
DROP TABLE IF EXISTS oauth2_client_registration;
DROP TABLE IF EXISTS oauth2_client_registration_info;
DROP TABLE IF EXISTS oauth2_client_registration_template;
DROP TABLE IF EXISTS api_usage_state;
DROP TABLE IF EXISTS resource;
DROP TABLE IF EXISTS firmware;

24
rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java

@ -103,7 +103,7 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationTemplate;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientsParams;
import org.thingsboard.server.common.data.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
@ -142,7 +142,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
@ -1773,21 +1772,28 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
}).getBody();
}
public List<OAuth2ClientInfo> getOAuth2Clients() {
public List<OAuth2ClientInfo> getOAuth2Clients(String pkgName) {
Map<String, String> params = new HashMap<>();
StringBuilder urlBuilder = new StringBuilder(baseURL);
urlBuilder.append("/api/noauth/oauth2Clients");
if (pkgName != null) {
urlBuilder.append("?pkgName={pkgName}");
params.put("pkgName", pkgName);
}
return restTemplate.exchange(
baseURL + "/api/noauth/oauth2Clients",
urlBuilder.toString(),
HttpMethod.POST,
HttpEntity.EMPTY,
new ParameterizedTypeReference<List<OAuth2ClientInfo>>() {
}).getBody();
}, params).getBody();
}
public OAuth2ClientsParams getCurrentOAuth2Params() {
return restTemplate.getForEntity(baseURL + "/api/oauth2/config", OAuth2ClientsParams.class).getBody();
public OAuth2Info getCurrentOAuth2Info() {
return restTemplate.getForEntity(baseURL + "/api/oauth2/config", OAuth2Info.class).getBody();
}
public OAuth2ClientsParams saveOAuth2Params(OAuth2ClientsParams oauth2Params) {
return restTemplate.postForEntity(baseURL + "/api/oauth2/config", oauth2Params, OAuth2ClientsParams.class).getBody();
public OAuth2Info saveOAuth2Info(OAuth2Info oauth2Info) {
return restTemplate.postForEntity(baseURL + "/api/oauth2/config", oauth2Info, OAuth2Info.class).getBody();
}
public String getLoginProcessingUrl() {

7
ui-ngx/src/app/core/auth/auth.service.ts

@ -44,8 +44,8 @@ import { AdminService } from '@core/http/admin.service';
import { ActionNotificationShow } from '@core/notification/notification.actions';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { AlertDialogComponent } from '@shared/components/dialog/alert-dialog.component';
import { OAuth2ClientInfo } from '@shared/models/oauth2.models';
import { isMobileApp } from '@core/utils';
import { OAuth2ClientInfo, PlatformType } from '@shared/models/oauth2.models';
import { isDefinedAndNotNull, isMobileApp } from '@core/utils';
@Injectable({
providedIn: 'root'
@ -205,7 +205,8 @@ export class AuthService {
}
public loadOAuth2Clients(): Observable<Array<OAuth2ClientInfo>> {
return this.http.post<Array<OAuth2ClientInfo>>(`/api/noauth/oauth2Clients`,
const url = '/api/noauth/oauth2Clients?platform=' + PlatformType.WEB;
return this.http.post<Array<OAuth2ClientInfo>>(url,
null, defaultHttpOptions()).pipe(
catchError(err => of([])),
tap((OAuth2Clients) => {

24
ui-ngx/src/app/core/http/device-profile.service.ts

@ -18,20 +18,22 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { PageLink } from '@shared/models/page/page-link';
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { Observable, throwError } from 'rxjs';
import { Observable, of, throwError } from 'rxjs';
import { PageData } from '@shared/models/page/page-data';
import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models';
import { isDefinedAndNotNull, isEmptyStr } from '@core/utils';
import { ObjectLwM2M, ServerSecurityConfig } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models';
import { SortOrder } from '@shared/models/page/sort-order';
import { OtaPackageService } from '@core/http/ota-package.service';
import { mergeMap } from 'rxjs/operators';
import { mergeMap, tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class DeviceProfileService {
private lwm2mBootstrapSecurityInfoInMemoryCache = new Map<boolean, ServerSecurityConfig>();
constructor(
private http: HttpClient,
private otaPackageService: OtaPackageService
@ -58,12 +60,18 @@ export class DeviceProfileService {
return this.http.get<Array<ObjectLwM2M>>(url, defaultHttpOptionsFromConfig(config));
}
public getLwm2mBootstrapSecurityInfo(securityMode: string, bootstrapServerIs: boolean,
config?: RequestConfig): Observable<ServerSecurityConfig> {
return this.http.get<ServerSecurityConfig>(
`/api/lwm2m/deviceProfile/bootstrap/${securityMode}/${bootstrapServerIs}`,
defaultHttpOptionsFromConfig(config)
);
public getLwm2mBootstrapSecurityInfo(isBootstrapServer: boolean, config?: RequestConfig): Observable<ServerSecurityConfig> {
const securityConfig = this.lwm2mBootstrapSecurityInfoInMemoryCache.get(isBootstrapServer);
if (securityConfig) {
return of(securityConfig);
} else {
return this.http.get<ServerSecurityConfig>(
`/api/lwm2m/deviceProfile/bootstrap/${isBootstrapServer}`,
defaultHttpOptionsFromConfig(config)
).pipe(
tap(serverConfig => this.lwm2mBootstrapSecurityInfoInMemoryCache.set(isBootstrapServer, serverConfig))
);
}
}
public getLwm2mObjectsPage(pageLink: PageLink, config?: RequestConfig): Observable<Array<ObjectLwM2M>> {

10
ui-ngx/src/app/core/http/oauth2.service.ts

@ -18,7 +18,7 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils';
import { Observable } from 'rxjs';
import { OAuth2ClientRegistrationTemplate, OAuth2ClientsParams } from '@shared/models/oauth2.models';
import { OAuth2ClientRegistrationTemplate, OAuth2Info } from '@shared/models/oauth2.models';
@Injectable({
providedIn: 'root'
@ -29,16 +29,16 @@ export class OAuth2Service {
private http: HttpClient
) { }
public getOAuth2Settings(config?: RequestConfig): Observable<OAuth2ClientsParams> {
return this.http.get<OAuth2ClientsParams>(`/api/oauth2/config`, defaultHttpOptionsFromConfig(config));
public getOAuth2Settings(config?: RequestConfig): Observable<OAuth2Info> {
return this.http.get<OAuth2Info>(`/api/oauth2/config`, defaultHttpOptionsFromConfig(config));
}
public getOAuth2Template(config?: RequestConfig): Observable<Array<OAuth2ClientRegistrationTemplate>> {
return this.http.get<Array<OAuth2ClientRegistrationTemplate>>(`/api/oauth2/config/template`, defaultHttpOptionsFromConfig(config));
}
public saveOAuth2Settings(OAuth2Setting: OAuth2ClientsParams, config?: RequestConfig): Observable<OAuth2ClientsParams> {
return this.http.post<OAuth2ClientsParams>('/api/oauth2/config', OAuth2Setting,
public saveOAuth2Settings(OAuth2Setting: OAuth2Info, config?: RequestConfig): Observable<OAuth2Info> {
return this.http.post<OAuth2Info>('/api/oauth2/config', OAuth2Setting,
defaultHttpOptionsFromConfig(config));
}

11
ui-ngx/src/app/core/utils.ts

@ -445,3 +445,14 @@ export function validateEntityId(entityId: EntityId | null): boolean {
export function isMobileApp(): boolean {
return isDefined((window as any).flutter_inappwebview);
}
const alphanumericCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const alphanumericCharactersLength = alphanumericCharacters.length;
export function randomAlphanumeric(length: number): string {
let result = '';
for ( let i = 0; i < length; i++ ) {
result += alphanumericCharacters.charAt(Math.floor(Math.random() * alphanumericCharactersLength));
}
return result;
}

71
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html

@ -28,60 +28,45 @@
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.server-host' | translate }}</mat-label>
<input matInput type="text" formControlName="host" required
matTooltip="{{'device-profile.lwm2m.server-host-tip' | translate}}"
matTooltipPosition="above">
<input matInput type="text" formControlName="host" required>
<mat-error *ngIf="serverFormGroup.get('host').hasError('required')">
{{ 'device-profile.lwm2m.server-host' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
{{ 'device-profile.lwm2m.server-host-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.server-port' | translate }}</mat-label>
<input matInput type="number" formControlName="port" required
matTooltip="{{'device-profile.lwm2m.server-port-tip' | translate}}"
matTooltipPosition="above">
<input matInput type="number" formControlName="port" required min="0">
<mat-error *ngIf="serverFormGroup.get('port').hasError('required')">
{{ 'device-profile.lwm2m.server-port' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
{{ 'device-profile.lwm2m.server-port-required' | translate }}
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
<input matInput type="number" formControlName="serverId" required
matTooltip="{{'device-profile.lwm2m.short-id-tip' | translate}}"
matTooltipPosition="above">
<input matInput type="number" formControlName="serverId" required min="0">
<mat-error *ngIf="serverFormGroup.get('serverId').hasError('required')">
{{ 'device-profile.lwm2m.short-id' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
{{ 'device-profile.lwm2m.short-id-required' | translate }}
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}</mat-label>
<input matInput type="number" formControlName="clientHoldOffTime" required
matTooltip="{{'device-profile.lwm2m.client-hold-off-time-tip' | translate}}"
<input matInput type="number" formControlName="clientHoldOffTime" required min="0"
matTooltip="{{'device-profile.lwm2m.client-hold-off-time-tooltip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('clientHoldOffTime').hasError('required')">
{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
{{ 'device-profile.lwm2m.client-hold-off-time-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.bootstrap-server-account-timeout' | translate }}</mat-label>
<input matInput type="number" formControlName="bootstrapServerAccountTimeout" required
matTooltip="{{'device-profile.lwm2m.bootstrap-server-account-timeout-tip' | translate}}"
<mat-label>{{ 'device-profile.lwm2m.account-after-timeout' | translate }}</mat-label>
<input matInput type="number" formControlName="bootstrapServerAccountTimeout" required min="0"
matTooltip="{{'device-profile.lwm2m.account-after-timeout-tooltip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('bootstrapServerAccountTimeout').hasError('required')">
{{ 'device-profile.lwm2m.bootstrap-server-account-timeout' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
{{ 'device-profile.lwm2m.account-after-timeout-required' | translate }}
</mat-error>
</mat-form-field>
<mat-checkbox fxFlex formControlName="bootstrapServerIs" color="primary">
{{ 'device-profile.lwm2m.bootstrap-server' | translate }}
</mat-checkbox>
<div fxFlex></div>
</div>
<div *ngIf="serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509">
@ -89,32 +74,22 @@
<mat-label>{{ 'device-profile.lwm2m.server-public-key' | translate }}</mat-label>
<textarea matInput
#serverPublicKey
maxlength="{{lenMaxServerPublicKey}}"
maxlength="{{maxLengthPublicKey}}"
cdkTextareaAutosize
cdkAutosizeMinRows="1"
cols="1" required
style="overflow:hidden"
formControlName="serverPublicKey"
matTooltip="{{'device-profile.lwm2m.server-public-key-tip' | translate}}"
></textarea>
<mat-hint align="end">{{serverPublicKey.value?.length || 0}}/{{lenMaxServerPublicKey}}</mat-hint>
<mat-hint align="end">{{serverPublicKey.value?.length || 0}}/{{maxLengthPublicKey}}</mat-hint>
<mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('required')">
{{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
{{ 'device-profile.lwm2m.server-public-key-required' | translate }}
</mat-error>
<mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('pattern') &&
(serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509)">
{{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ 'device-profile.lwm2m.pattern_hex_dec' | translate: {
count: 0} }}</strong>
<mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('pattern')">
{{ 'device-profile.lwm2m.server-public-key-pattern' | translate }}
</mat-error>
<mat-error *ngIf="(serverFormGroup.get('serverPublicKey').hasError('maxlength') ||
serverFormGroup.get('serverPublicKey').hasError('minlength')) &&
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK">
{{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ 'device-profile.lwm2m.pattern_hex_dec' | translate: {
count: lenMaxServerPublicKey } }}</strong>
<mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('maxlength') ||
serverFormGroup.get('serverPublicKey').hasError('minlength')">
{{ 'device-profile.lwm2m.server-public-key-length' | translate: {count: maxLengthPublicKey } }}
</mat-error>
</mat-form-field>
</div>

244
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts

@ -14,26 +14,24 @@
/// limitations under the License.
///
import { Component, forwardRef, Inject, Input } from '@angular/core';
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import {
DEFAULT_CLIENT_HOLD_OFF_TIME,
DEFAULT_ID_SERVER,
DEFAULT_PORT_BOOTSTRAP_NO_SEC,
DEFAULT_PORT_SERVER_NO_SEC,
KEY_REGEXP_HEX_DEC,
LEN_MAX_PUBLIC_KEY_RPK,
LEN_MAX_PUBLIC_KEY_X509,
SECURITY_CONFIG_MODE,
SECURITY_CONFIG_MODE_NAMES,
securityConfigMode,
securityConfigModeNames,
ServerSecurityConfig
} from './lwm2m-profile-config.models';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { WINDOW } from '@core/services/window.service';
import { pairwise, startWith } from 'rxjs/operators';
import { DeviceProfileService } from '@core/http/device-profile.service';
import { of, Subject } from 'rxjs';
import { map, mergeMap, takeUntil, tap } from 'rxjs/operators';
import { Observable } from 'rxjs/internal/Observable';
import { deepClone } from '@core/utils';
// @dynamic
@Component({
selector: 'tb-profile-lwm2m-device-config-server',
templateUrl: './lwm2m-device-config-server.component.html',
@ -46,127 +44,78 @@ import { DeviceProfileService } from '@core/http/device-profile.service';
]
})
export class Lwm2mDeviceConfigServerComponent implements ControlValueAccessor {
export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, OnDestroy {
private requiredValue: boolean;
private disabled = false;
private destroy$ = new Subject();
private securityDefaultConfig: ServerSecurityConfig;
valuePrev = null;
serverFormGroup: FormGroup;
securityConfigLwM2MType = SECURITY_CONFIG_MODE;
securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE);
credentialTypeLwM2MNamesMap = SECURITY_CONFIG_MODE_NAMES;
lenMinServerPublicKey = 0;
lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK;
securityConfigLwM2MType = securityConfigMode;
securityConfigLwM2MTypes = Object.keys(securityConfigMode);
credentialTypeLwM2MNamesMap = securityConfigModeNames;
maxLengthPublicKey = LEN_MAX_PUBLIC_KEY_RPK;
currentSecurityMode = null;
@Input()
bootstrapServerIs: boolean;
isBootstrapServer = false;
get required(): boolean {
return this.requiredValue;
}
private propagateChange = (v: any) => { };
@Input()
set required(value: boolean) {
this.requiredValue = coerceBooleanProperty(value);
constructor(public fb: FormBuilder,
private deviceProfileService: DeviceProfileService) {
}
constructor(public fb: FormBuilder,
private deviceProfileService: DeviceProfileService,
@Inject(WINDOW) private window: Window) {
this.serverFormGroup = this.initServerGroup();
ngOnInit(): void {
this.serverFormGroup = this.fb.group({
host: ['', Validators.required],
port: [this.isBootstrapServer ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC, [Validators.required, Validators.min(0)]],
securityMode: [securityConfigMode.NO_SEC],
serverPublicKey: ['', Validators.required],
clientHoldOffTime: ['', [Validators.required, Validators.min(0)]],
serverId: ['', [Validators.required, Validators.min(0)]],
bootstrapServerAccountTimeout: ['', [Validators.required, Validators.min(0)]],
});
this.serverFormGroup.get('securityMode').valueChanges.pipe(
startWith(null),
pairwise()
).subscribe(([previousValue, currentValue]) => {
if (previousValue === null || previousValue !== currentValue) {
this.getLwm2mBootstrapSecurityInfo(currentValue);
this.updateValidate(currentValue);
this.serverFormGroup.updateValueAndValidity();
}
tap(securityMode => this.updateValidate(securityMode)),
mergeMap(securityMode => this.getLwm2mBootstrapSecurityInfo(securityMode)),
takeUntil(this.destroy$)
).subscribe(serverSecurityConfig => {
this.serverFormGroup.patchValue(serverSecurityConfig, {emitEvent: false});
});
this.serverFormGroup.valueChanges.subscribe(value => {
if (this.disabled !== undefined && !this.disabled) {
this.propagateChangeState(value);
}
this.serverFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(value => {
this.propagateChangeState(value);
});
}
private updateValueFields = (serverData: ServerSecurityConfig): void => {
serverData.bootstrapServerIs = this.bootstrapServerIs;
this.serverFormGroup.patchValue(serverData, {emitEvent: false});
this.serverFormGroup.get('bootstrapServerIs').disable();
const securityMode = this.serverFormGroup.get('securityMode').value as SECURITY_CONFIG_MODE;
this.updateValidate(securityMode);
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
private updateValidate = (securityMode: SECURITY_CONFIG_MODE): void => {
switch (securityMode) {
case SECURITY_CONFIG_MODE.NO_SEC:
this.setValidatorsNoSecPsk();
break;
case SECURITY_CONFIG_MODE.PSK:
this.setValidatorsNoSecPsk();
break;
case SECURITY_CONFIG_MODE.RPK:
this.lenMinServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK;
this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK;
this.setValidatorsRpkX509();
break;
case SECURITY_CONFIG_MODE.X509:
this.lenMinServerPublicKey = 0;
this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_X509;
this.setValidatorsRpkX509();
break;
writeValue(serverData: ServerSecurityConfig): void {
if (serverData) {
this.serverFormGroup.patchValue(serverData, {emitEvent: false});
this.updateValidate(serverData.securityMode);
}
this.serverFormGroup.updateValueAndValidity();
}
private setValidatorsNoSecPsk = (): void => {
this.serverFormGroup.get('serverPublicKey').setValidators([]);
}
private setValidatorsRpkX509 = (): void => {
this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required,
Validators.pattern(KEY_REGEXP_HEX_DEC),
Validators.minLength(this.lenMinServerPublicKey),
Validators.maxLength(this.lenMaxServerPublicKey)]);
}
writeValue(value: ServerSecurityConfig): void {
if (value) {
this.updateValueFields(value);
if (!this.securityDefaultConfig){
this.getLwm2mBootstrapSecurityInfo().subscribe(value => {
if (!serverData) {
this.serverFormGroup.patchValue(value);
}
});
}
}
private propagateChange = (v: any) => {};
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
private propagateChangeState = (value: any): void => {
if (value !== undefined) {
if (this.valuePrev === null) {
this.valuePrev = 'init';
} else if (this.valuePrev === 'init') {
this.valuePrev = value;
} else if (JSON.stringify(value) !== JSON.stringify(this.valuePrev)) {
this.valuePrev = value;
if (this.serverFormGroup.valid) {
this.propagateChange(value);
} else {
this.propagateChange(null);
}
}
}
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
this.valuePrev = null;
if (isDisabled) {
this.serverFormGroup.disable({emitEvent: false});
} else {
@ -177,33 +126,76 @@ export class Lwm2mDeviceConfigServerComponent implements ControlValueAccessor {
registerOnTouched(fn: any): void {
}
private initServerGroup = (): FormGroup => {
const port = this.bootstrapServerIs ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC;
return this.fb.group({
host: [this.window.location.hostname, this.required ? Validators.required : ''],
port: [port, this.required ? Validators.required : ''],
bootstrapServerIs: [this.bootstrapServerIs, ''],
securityMode: [this.fb.control(SECURITY_CONFIG_MODE.NO_SEC)],
serverPublicKey: ['', this.required ? Validators.required : ''],
clientHoldOffTime: [DEFAULT_CLIENT_HOLD_OFF_TIME, this.required ? Validators.required : ''],
serverId: [DEFAULT_ID_SERVER, this.required ? Validators.required : ''],
bootstrapServerAccountTimeout: ['', this.required ? Validators.required : ''],
});
private updateValidate(securityMode: securityConfigMode): void {
switch (securityMode) {
case securityConfigMode.NO_SEC:
case securityConfigMode.PSK:
this.clearValidators();
break;
case securityConfigMode.RPK:
this.maxLengthPublicKey = LEN_MAX_PUBLIC_KEY_RPK;
this.setValidators(LEN_MAX_PUBLIC_KEY_RPK);
break;
case securityConfigMode.X509:
this.maxLengthPublicKey = LEN_MAX_PUBLIC_KEY_X509;
this.setValidators(0);
break;
}
this.serverFormGroup.get('serverPublicKey').updateValueAndValidity({emitEvent: false});
}
private clearValidators(): void {
this.serverFormGroup.get('serverPublicKey').clearValidators();
}
private setValidators(minLengthKey: number): void {
this.serverFormGroup.get('serverPublicKey').setValidators([
Validators.required,
Validators.pattern(KEY_REGEXP_HEX_DEC),
Validators.minLength(minLengthKey),
Validators.maxLength(this.maxLengthPublicKey)
]);
}
private getLwm2mBootstrapSecurityInfo = (mode: string): void => {
this.deviceProfileService.getLwm2mBootstrapSecurityInfo(mode, this.serverFormGroup.get('bootstrapServerIs').value).subscribe(
(serverSecurityConfig) => {
this.serverFormGroup.patchValue({
host: serverSecurityConfig.host,
port: serverSecurityConfig.port,
serverPublicKey: serverSecurityConfig.serverPublicKey,
clientHoldOffTime: serverSecurityConfig.clientHoldOffTime,
serverId: serverSecurityConfig.serverId,
bootstrapServerAccountTimeout: serverSecurityConfig.bootstrapServerAccountTimeout
},
{emitEvent: true});
private propagateChangeState = (value: ServerSecurityConfig): void => {
if (value !== undefined) {
if (this.serverFormGroup.valid) {
this.propagateChange(value);
} else {
this.propagateChange(null);
}
}
}
private getLwm2mBootstrapSecurityInfo(securityMode = securityConfigMode.NO_SEC): Observable<ServerSecurityConfig> {
if (this.securityDefaultConfig) {
return of(this.processingBootstrapSecurityInfo(this.securityDefaultConfig, securityMode));
}
return this.deviceProfileService.getLwm2mBootstrapSecurityInfo(this.isBootstrapServer).pipe(
map(securityInfo => {
this.securityDefaultConfig = securityInfo;
return this.processingBootstrapSecurityInfo(securityInfo, securityMode);
})
);
}
private processingBootstrapSecurityInfo(securityConfig: ServerSecurityConfig, securityMode: securityConfigMode): ServerSecurityConfig {
const config = deepClone(securityConfig);
switch (securityMode) {
case securityConfigMode.PSK:
config.port = config.securityPort;
config.host = config.securityHost;
config.serverPublicKey = '';
break;
case securityConfigMode.RPK:
case securityConfigMode.X509:
config.port = config.securityPort;
config.host = config.securityHost;
break;
case securityConfigMode.NO_SEC:
config.serverPublicKey = '';
break;
}
return config;
}
}

285
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html

@ -15,175 +15,172 @@
limitations under the License.
-->
<section style="padding-bottom: 16px; margin: 0" mat-dialog-content>
<section style="padding-bottom: 16px; margin: 0">
<mat-tab-group dynamicHeight>
<mat-tab label="{{ 'device-profile.lwm2m.model-tab' | translate }}">
<ng-template matTabContent>
<section [formGroup]="lwm2mDeviceProfileFormGroup">
<div class="mat-padding" style="padding-top: 0">
<tb-profile-lwm2m-object-list
(addList)="addObjectsList($event)"
(removeList)="removeObjectsList($event)"
[required]="required"
formControlName="objectIds">
</tb-profile-lwm2m-object-list>
</div>
<div class="mat-padding">
<tb-profile-lwm2m-observe-attr-telemetry
[required]="required"
formControlName="observeAttrTelemetry">
</tb-profile-lwm2m-observe-attr-telemetry>
</div>
<tb-profile-lwm2m-object-list
(addList)="addObjectsList($event)"
(removeList)="removeObjectsList($event)"
[required]="required"
formControlName="objectIds">
</tb-profile-lwm2m-object-list>
<tb-profile-lwm2m-observe-attr-telemetry
[required]="required"
formControlName="observeAttrTelemetry">
</tb-profile-lwm2m-observe-attr-telemetry>
</section>
</ng-template>
</mat-tab>
<mat-tab label="{{ 'device-profile.lwm2m.bootstrap-tab' | translate }}">
<mat-tab label="{{ 'device-profile.lwm2m.servers' | translate }}">
<ng-template matTabContent>
<section [formGroup]="lwm2mDeviceProfileFormGroup">
<div class="mat-padding">
<mat-accordion multi="true" class="mat-body-1">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<div class="tb-panel-title">{{ 'device-profile.lwm2m.servers' | translate | uppercase }}</div>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div fxLayout="column">
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
<input matInput type="number" formControlName="shortId" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('shortId').hasError('required')">
{{ 'device-profile.lwm2m.short-id' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label>
<input matInput type="number" formControlName="lifetime" required>
<mat-error
*ngIf="lwm2mDeviceProfileFormGroup.get('lifetime').hasError('required')">
{{ 'device-profile.lwm2m.lifetime' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label>
<input matInput type="number" formControlName="defaultMinPeriod" required>
<mat-error
*ngIf="lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').hasError('required')">
{{ 'device-profile.lwm2m.default-min-period' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field class="mat-block" fxFlex="100">
<mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label>
<mat-select formControlName="binding">
<mat-option *ngFor="let bindingMode of bindingModeTypes"
[value]="bindingMode">
{{ bindingModeTypeNamesMap.get(bindingModeType[bindingMode]) }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div>
<mat-checkbox formControlName="notifIfDisabled" color="primary">
{{ 'device-profile.lwm2m.notif-if-disabled' | translate }}
</mat-checkbox>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</mat-accordion>
<mat-accordion multi="true" class="mat-body-1">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<div
class="tb-panel-title">{{ 'device-profile.lwm2m.bootstrap-server' | translate | uppercase }}</div>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="mat-padding">
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName="bootstrapServer"
[bootstrapServerIs]=true>
</tb-profile-lwm2m-device-config-server>
</div>
</ng-template>
</mat-expansion-panel>
</mat-accordion>
<mat-accordion multi="true" class="mat-body-1">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<div class="tb-panel-title">{{ 'device-profile.lwm2m.lwm2m-server' | translate | uppercase }}</div>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="mat-padding">
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName="lwm2mServer"
[bootstrapServerIs]=false>
</tb-profile-lwm2m-device-config-server>
</div>
</ng-template>
</mat-expansion-panel>
</mat-accordion>
</div>
<section [formGroup]="lwm2mDeviceProfileFormGroup" style="padding: 4px 2px">
<mat-accordion multi="true">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>{{ 'device-profile.lwm2m.servers' | translate }}</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
<input matInput type="number" formControlName="shortId" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('shortId').hasError('required')">
{{ 'device-profile.lwm2m.short-id' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label>
<input matInput type="number" formControlName="lifetime" required>
<mat-error
*ngIf="lwm2mDeviceProfileFormGroup.get('lifetime').hasError('required')">
{{ 'device-profile.lwm2m.lifetime' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label>
<input matInput type="number" formControlName="defaultMinPeriod" required>
<mat-error
*ngIf="lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').hasError('required')">
{{ 'device-profile.lwm2m.default-min-period' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
</div>
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label>
<mat-select formControlName="binding">
<mat-option *ngFor="let bindingMode of bindingModeTypes"
[value]="bindingMode">
{{ bindingModeTypeNamesMap.get(bindingModeType[bindingMode]) }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-checkbox formControlName="notifIfDisabled" color="primary">
{{ 'device-profile.lwm2m.notif-if-disabled' | translate }}
</mat-checkbox>
</ng-template>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>{{ 'device-profile.lwm2m.bootstrap-server' | translate }}</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName="bootstrapServer"
[isBootstrapServer]="true">
</tb-profile-lwm2m-device-config-server>
</ng-template>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>{{ 'device-profile.lwm2m.lwm2m-server' | translate }}</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName="lwm2mServer"
[isBootstrapServer]="false">
</tb-profile-lwm2m-device-config-server>
</ng-template>
</mat-expansion-panel>
</mat-accordion>
</section>
</ng-template>
</mat-tab>
<mat-tab label="{{ 'device-profile.lwm2m.others-tab' | translate }}">
<ng-template matTabContent>
<section [formGroup]="lwm2mDeviceProfileFormGroup">
<div *ngIf="false" class="mat-padding" style="padding-bottom: 0px">
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.client-strategy-label' | translate }}</mat-label>
<mat-select formControlName="clientStrategy"
matTooltip="{{ 'device-profile.lwm2m.client-strategy-tip' | translate:
{ count: +lwm2mDeviceProfileFormGroup.get('clientStrategy').value } }}"
matTooltipPosition="above">
<mat-option value=1>{{ 'device-profile.lwm2m.client-strategy' | translate:
{count: 1} }}</mat-option>
<mat-option value=2>{{ 'device-profile.lwm2m.client-strategy' | translate:
{count: 2} }}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="mat-padding" style="padding-bottom: 0px">
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.fw-update-strategy-label' | translate }}</mat-label>
<fieldset class="fields-group">
<legend class="group-title" translate>device-profile.lwm2m.fw-update</legend>
<mat-form-field class="mat-block" fxFlex>
<mat-label>{{ 'device-profile.lwm2m.fw-update-strategy' | translate }}</mat-label>
<mat-select formControlName="fwUpdateStrategy">
<mat-option value=1>{{ 'device-profile.lwm2m.fw-update-strategy' | translate:
{count: 1} }}</mat-option>
<mat-option value=2>{{ 'device-profile.lwm2m.fw-update-strategy' | translate:
{count: 2} }}</mat-option>
<mat-option value=2>{{ 'device-profile.lwm2m.fw-update-strategy' | translate:
{count: 3} }}</mat-option>
<mat-option [value]=1>{{ 'device-profile.lwm2m.fw-update-strategy-package' | translate }}</mat-option>
<mat-option [value]=2>{{ 'device-profile.lwm2m.fw-update-strategy-package-uri' | translate }}</mat-option>
<mat-option [value]=3>{{ 'device-profile.lwm2m.fw-update-strategy-data' | translate }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.sw-update-strategy-label' | translate }}</mat-label>
<mat-form-field class="mat-block" fxFlex *ngIf="isFwUpdateStrategy">
<mat-label>{{ 'device-profile.lwm2m.fw-update-recourse' | translate }}</mat-label>
<input matInput formControlName="fwUpdateRecourse" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').hasError('required')">
{{ 'device-profile.lwm2m.fw-update-recourse-required' | translate }}
</mat-error>
</mat-form-field>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>device-profile.lwm2m.sw-update</legend>
<mat-form-field class="mat-block" fxFlex>
<mat-label>{{ 'device-profile.lwm2m.sw-update-strategy' | translate }}</mat-label>
<mat-select formControlName="swUpdateStrategy">
<mat-option value=1>{{ 'device-profile.lwm2m.sw-update-strategy' | translate:
{count: 1} }}</mat-option>
<mat-option value=2>{{ 'device-profile.lwm2m.sw-update-strategy' | translate:
{count: 2} }}</mat-option>
<mat-option [value]=1>{{ 'device-profile.lwm2m.sw-update-strategy-package' | translate }}</mat-option>
<mat-option [value]=2>{{ 'device-profile.lwm2m.sw-update-strategy-package-uri' | translate }}</mat-option>
</mat-select>
</mat-form-field>
</div>
<mat-form-field class="mat-block" fxFlex *ngIf="isSwUpdateStrategy">
<mat-label>{{ 'device-profile.lwm2m.sw-update-recourse' | translate }}</mat-label>
<input matInput formControlName="swUpdateRecourse" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').hasError('required')">
{{ 'device-profile.lwm2m.sw-update-recourse-required' | translate }}
</mat-error>
</mat-form-field>
</fieldset>
<!-- <mat-accordion multi="true">-->
<!-- <div *ngIf="false">-->
<!-- <mat-expansion-panel>-->
<!-- <mat-expansion-panel-header>-->
<!-- <mat-panel-title>{{ 'device-profile.lwm2m.client-strategy' | translate }}</mat-panel-title>-->
<!-- </mat-expansion-panel-header>-->
<!-- <ng-template matExpansionPanelContent>-->
<!-- <div fxLayout="column">-->
<!-- <mat-form-field class="mat-block">-->
<!-- <mat-label>{{ 'device-profile.lwm2m.client-strategy-label' | translate }}</mat-label>-->
<!-- <mat-select formControlName="clientStrategy"-->
<!-- matTooltip="{{ 'device-profile.lwm2m.client-strategy-tip' | translate:-->
<!-- { count: +lwm2mDeviceProfileFormGroup.get('clientStrategy').value } }}"-->
<!-- matTooltipPosition="above">-->
<!-- <mat-option value=1>{{ 'device-profile.lwm2m.client-strategy-connect' | translate:-->
<!-- {count: 1} }}</mat-option>-->
<!-- <mat-option value=2>{{ 'device-profile.lwm2m.client-strategy-connect' | translate:-->
<!-- {count: 2} }}</mat-option>-->
<!-- </mat-select>-->
<!-- </mat-form-field>-->
<!-- </div>-->
<!-- </ng-template>-->
<!-- </mat-expansion-panel>-->
<!-- </div>-->
<!-- </mat-accordion>-->
</section>
</ng-template>
</mat-tab>
<mat-tab label="{{ 'device-profile.lwm2m.config-json-tab' | translate }}">
<ng-template matTabContent>
<section [formGroup]="lwm2mDeviceConfigFormGroup" class="mat-padding">
<section [formGroup]="lwm2mDeviceConfigFormGroup" style="padding: 8px 0">
<tb-json-object-edit
[required]="required"
[sort]="sortFunction"

27
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.scss

@ -0,0 +1,27 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host{
.fields-group {
padding: 8px;
margin: 10px 0;
border: 1px groove rgba(0, 0, 0, .25);
border-radius: 4px;
legend {
color: rgba(0, 0, 0, .7);
}
}
}

74
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts

@ -22,6 +22,8 @@ import {
ATTRIBUTE,
BINDING_MODE,
BINDING_MODE_NAMES,
DEFAULT_FW_UPDATE_RESOURCE,
DEFAULT_SW_UPDATE_RESOURCE,
getDefaultProfileConfig,
Instance,
INSTANCES,
@ -45,6 +47,7 @@ import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'tb-profile-lwm2m-device-transport-configuration',
templateUrl: './lwm2m-device-profile-transport-configuration.component.html',
styleUrls: ['./lwm2m-device-profile-transport-configuration.component.scss'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Lwm2mDeviceProfileTransportConfigurationComponent),
@ -67,6 +70,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
bootstrapServer: string;
lwm2mServer: string;
sortFunction: (key: string, value: object) => object;
isFwUpdateStrategy: boolean;
isSwUpdateStrategy: boolean;
get required(): boolean {
return this.requiredValue;
@ -95,10 +100,38 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
clientStrategy: [1, []],
fwUpdateStrategy: [1, []],
swUpdateStrategy: [1, []],
fwUpdateRecourse: [{value: '', disabled: true}, []],
swUpdateRecourse: [{value: '', disabled: true}, []]
});
this.lwm2mDeviceConfigFormGroup = this.fb.group({
configurationJson: [null, Validators.required]
});
this.lwm2mDeviceProfileFormGroup.get('fwUpdateStrategy').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((fwStrategy) => {
if (fwStrategy === 2) {
this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').enable({emitEvent: false});
this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').patchValue(DEFAULT_FW_UPDATE_RESOURCE, {emitEvent: false});
this.isFwUpdateStrategy = true;
} else {
this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').disable({emitEvent: false});
this.isFwUpdateStrategy = false;
}
this.otaUpdateFwStrategyValidate(true);
});
this.lwm2mDeviceProfileFormGroup.get('swUpdateStrategy').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((swStrategy) => {
if (swStrategy === 2) {
this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').enable({emitEvent: false});
this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').patchValue(DEFAULT_SW_UPDATE_RESOURCE, {emitEvent: false});
this.isSwUpdateStrategy = true;
} else {
this.isSwUpdateStrategy = false;
this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').disable({emitEvent: false});
}
this.otaUpdateSwStrategyValidate(true);
});
this.lwm2mDeviceProfileFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((value) => {
@ -169,6 +202,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
}
private updateWriteValue = (value: ModelValue): void => {
const fwResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateRecourse) ?
this.configurationValue.clientLwM2mSettings.fwUpdateRecourse : '';
const swResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateRecourse) ?
this.configurationValue.clientLwM2mSettings.swUpdateRecourse : '';
this.lwm2mDeviceProfileFormGroup.patchValue({
objectIds: value,
observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value.objectsList),
@ -180,10 +217,18 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
bootstrapServer: this.configurationValue.bootstrap.bootstrapServer,
lwm2mServer: this.configurationValue.bootstrap.lwm2mServer,
clientStrategy: this.configurationValue.clientLwM2mSettings.clientStrategy,
fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy,
swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy
fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1,
swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1,
fwUpdateRecourse: fwResource,
swUpdateRecourse: swResource
},
{emitEvent: false});
this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = fwResource;
this.configurationValue.clientLwM2mSettings.swUpdateRecourse = swResource;
this.isFwUpdateStrategy = this.configurationValue.clientLwM2mSettings.fwUpdateStrategy === 2;
this.isSwUpdateStrategy = this.configurationValue.clientLwM2mSettings.swUpdateStrategy === 2;
this.otaUpdateSwStrategyValidate();
this.otaUpdateFwStrategyValidate();
}
private updateModel = (): void => {
@ -215,9 +260,11 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.configurationValue.clientLwM2mSettings.clientStrategy = config.clientStrategy;
this.configurationValue.clientLwM2mSettings.fwUpdateStrategy = config.fwUpdateStrategy;
this.configurationValue.clientLwM2mSettings.swUpdateStrategy = config.swUpdateStrategy;
this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = config.fwUpdateRecourse;
this.configurationValue.clientLwM2mSettings.swUpdateRecourse = config.swUpdateRecourse;
this.upDateJsonAllConfig();
this.updateModel();
}
this.updateModel();
}
private getObserveAttrTelemetryObjects = (objectList: ObjectLwM2M[]): object => {
@ -264,7 +311,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
const pathParameter = Array.from(path.split('/'), String);
const objectLwM2M = clientObserveAttrTelemetry.find(x => x.keyId === pathParameter[0]);
if (objectLwM2M) {
const instance = this.updateInInstanceKeyName (objectLwM2M.instances[0], +pathParameter[1]);
const instance = this.updateInInstanceKeyName(objectLwM2M.instances[0], +pathParameter[1]);
objectLwM2M.instances.push(instance);
}
});
@ -489,4 +536,23 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
}
});
}
private otaUpdateFwStrategyValidate(updated = false): void {
if (this.isFwUpdateStrategy) {
this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').setValidators([Validators.required]);
} else {
this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').clearValidators();
}
this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').updateValueAndValidity({emitEvent: updated});
}
private otaUpdateSwStrategyValidate(updated = false): void {
if (this.isSwUpdateStrategy) {
this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').setValidators([Validators.required]);
} else {
this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').clearValidators();
}
this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').updateValueAndValidity({emitEvent: updated});
}
}

45
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts

@ -20,7 +20,6 @@ export const INSTANCE = 'instance';
export const RESOURCES = 'resources';
export const ATTRIBUTE_LWM2M = 'attributeLwm2m';
export const CLIENT_LWM2M = 'clientLwM2M';
export const CLIENT_LWM2M_SETTINGS = 'clientLwM2mSettings';
export const OBSERVE_ATTR_TELEMETRY = 'observeAttrTelemetry';
export const OBSERVE = 'observe';
export const ATTRIBUTE = 'attribute';
@ -28,7 +27,7 @@ export const TELEMETRY = 'telemetry';
export const KEY_NAME = 'keyName';
export const DEFAULT_ID_SERVER = 123;
export const DEFAULT_ID_BOOTSTRAP = 111;
export const DEFAULT_HOST_NAME = 'localhost';
export const DEFAULT_LOCAL_HOST_NAME = 'localhost';
export const DEFAULT_PORT_SERVER_NO_SEC = 5685;
export const DEFAULT_PORT_BOOTSTRAP_NO_SEC = 5687;
export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1;
@ -43,6 +42,9 @@ export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/;
export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/;
export const INSTANCES_ID_VALUE_MIN = 0;
export const INSTANCES_ID_VALUE_MAX = 65535;
export const DEFAULT_OTA_UPDATE_PROTOCOL = 'coap://';
export const DEFAULT_FW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_LOCAL_HOST_NAME + ':' + DEFAULT_PORT_SERVER_NO_SEC;
export const DEFAULT_SW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_LOCAL_HOST_NAME + ':' + DEFAULT_PORT_SERVER_NO_SEC;
export enum BINDING_MODE {
@ -110,19 +112,19 @@ export const ATTRIBUTE_LWM2M_MAP = new Map<ATTRIBUTE_LWM2M_ENUM, string>(
export const ATTRIBUTE_KEYS = Object.keys(ATTRIBUTE_LWM2M_ENUM) as string[];
export enum SECURITY_CONFIG_MODE {
export enum securityConfigMode {
PSK = 'PSK',
RPK = 'RPK',
X509 = 'X509',
NO_SEC = 'NO_SEC'
}
export const SECURITY_CONFIG_MODE_NAMES = new Map<SECURITY_CONFIG_MODE, string>(
export const securityConfigModeNames = new Map<securityConfigMode, string>(
[
[SECURITY_CONFIG_MODE.PSK, 'Pre-Shared Key'],
[SECURITY_CONFIG_MODE.RPK, 'Raw Public Key'],
[SECURITY_CONFIG_MODE.X509, 'X.509 Certificate'],
[SECURITY_CONFIG_MODE.NO_SEC, 'No Security']
[securityConfigMode.PSK, 'Pre-Shared Key'],
[securityConfigMode.RPK, 'Raw Public Key'],
[securityConfigMode.X509, 'X.509 Certificate'],
[securityConfigMode.NO_SEC, 'No Security']
]
);
@ -141,9 +143,10 @@ export interface BootstrapServersSecurityConfig {
export interface ServerSecurityConfig {
host?: string;
securityHost?: string;
port?: number;
bootstrapServerIs?: boolean;
securityMode: string;
securityPort?: number;
securityMode: securityConfigMode;
clientPublicKeyOrId?: string;
clientSecretKey?: string;
serverPublicKey?: string;
@ -166,8 +169,10 @@ export interface Lwm2mProfileConfigModels {
export interface ClientLwM2mSettings {
clientStrategy: string;
fwUpdateStrategy: string;
swUpdateStrategy: string;
fwUpdateStrategy: number;
swUpdateStrategy: number;
fwUpdateRecourse: string;
swUpdateRecourse: string;
}
export interface ObservableAttributes {
@ -188,12 +193,11 @@ export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecu
};
}
export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSecurityConfig {
export function getDefaultBootstrapServerSecurityConfig(hostname: string): ServerSecurityConfig {
return {
host: hostname,
port: DEFAULT_PORT_BOOTSTRAP_NO_SEC,
bootstrapServerIs: true,
securityMode: SECURITY_CONFIG_MODE.NO_SEC.toString(),
securityMode: securityConfigMode.NO_SEC,
serverPublicKey: '',
clientHoldOffTime: DEFAULT_CLIENT_HOLD_OFF_TIME,
serverId: DEFAULT_ID_BOOTSTRAP,
@ -203,7 +207,6 @@ export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSe
export function getDefaultLwM2MServerSecurityConfig(hostname): ServerSecurityConfig {
const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(hostname);
DefaultLwM2MServerSecurityConfig.bootstrapServerIs = false;
DefaultLwM2MServerSecurityConfig.port = DEFAULT_PORT_SERVER_NO_SEC;
DefaultLwM2MServerSecurityConfig.serverId = DEFAULT_ID_SERVER;
return DefaultLwM2MServerSecurityConfig;
@ -231,15 +234,17 @@ export function getDefaultProfileConfig(hostname?: any): Lwm2mProfileConfigModel
return {
clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig(),
observeAttr: getDefaultProfileObserveAttrConfig(),
bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname) ? hostname : DEFAULT_HOST_NAME)
bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname) ? hostname : DEFAULT_LOCAL_HOST_NAME)
};
}
function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings {
return {
clientStrategy: "1",
fwUpdateStrategy: "1",
swUpdateStrategy: "1"
clientStrategy: '1',
fwUpdateStrategy: 1,
swUpdateStrategy: 1,
fwUpdateRecourse: DEFAULT_FW_UPDATE_RESOURCE,
swUpdateRecourse: DEFAULT_SW_UPDATE_RESOURCE
};
}

2
ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts

@ -772,7 +772,7 @@ function drawDigitalLabel(context: DigitalGaugeCanvasRenderingContext2D, options
context.textAlign = 'center';
context.font = Drawings.font(options, 'Label', fontSizeFactor);
context.lineWidth = 0;
drawText(context, options, 'Label', options.label.toUpperCase(), textX, textY);
drawText(context, options, 'Label', options.label, textX, textY);
}
function drawDigitalMinMax(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions) {

34
ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html

@ -48,20 +48,6 @@
<mat-label translate>device.label</mat-label>
<input matInput formControlName="label">
</mat-form-field>
<mat-form-field class="mat-block" style="padding-bottom: 14px;">
<mat-label translate>device-profile.transport-type</mat-label>
<mat-select formControlName="transportType" required>
<mat-option *ngFor="let type of deviceTransportTypes" [value]="type">
{{deviceTransportTypeTranslations.get(type) | translate}}
</mat-option>
</mat-select>
<mat-hint *ngIf="deviceWizardFormGroup.get('transportType').value">
{{deviceTransportTypeHints.get(deviceWizardFormGroup.get('transportType').value) | translate}}
</mat-hint>
<mat-error *ngIf="deviceWizardFormGroup.get('transportType').hasError('required')">
{{ 'device-profile.transport-type-required' | translate }}
</mat-error>
</mat-form-field>
<div fxLayout="row" fxLayoutGap="16px">
<mat-radio-group fxLayout="column" formControlName="addProfileType" fxLayoutAlign="space-around">
<mat-radio-button [value]="0" color="primary">
@ -74,13 +60,10 @@
<div fxLayout="column">
<tb-device-profile-autocomplete
[required]="!createProfile"
[transportType]="deviceWizardFormGroup.get('transportType').value"
formControlName="deviceProfileId"
[ngClass]="{invisible: deviceWizardFormGroup.get('addProfileType').value !== 0}"
(deviceProfileChanged)="$event?.transportType ? deviceWizardFormGroup.get('transportType').patchValue($event?.transportType) : {}"
[addNewProfile]="false"
[selectDefaultProfile]="true"
[selectFirstProfile]="true"
[editProfileEnabled]="false">
</tb-device-profile-autocomplete>
<mat-form-field fxFlex class="mat-block"
@ -124,9 +107,22 @@
</fieldset>
</form>
</mat-step>
<mat-step [stepControl]="transportConfigFormGroup" *ngIf="createTransportConfiguration">
<mat-step [stepControl]="transportConfigFormGroup" [optional]="true" *ngIf="createProfile">
<form [formGroup]="transportConfigFormGroup" style="padding-bottom: 16px;">
<ng-template matStepLabel>{{ 'device-profile.transport-configuration' | translate }}</ng-template>
<ng-template matStepLabel>{{ 'device-profile.transport-configuration' | translate }}</ng-template><mat-form-field class="mat-block" style="padding-bottom: 14px;">
<mat-label translate>device-profile.transport-type</mat-label>
<mat-select formControlName="transportType" required>
<mat-option *ngFor="let type of deviceTransportTypes" [value]="type">
{{deviceTransportTypeTranslations.get(type) | translate}}
</mat-option>
</mat-select>
<mat-hint *ngIf="transportConfigFormGroup.get('transportType').value">
{{deviceTransportTypeHints.get(transportConfigFormGroup.get('transportType').value) | translate}}
</mat-hint>
<mat-error *ngIf="transportConfigFormGroup.get('transportType').hasError('required')">
{{ 'device-profile.transport-type-required' | translate }}
</mat-error>
</mat-form-field>
<tb-device-profile-transport-configuration
formControlName="transportConfiguration"
required>

18
ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts

@ -29,7 +29,6 @@ import {
DeviceProvisionConfiguration,
DeviceProvisionType,
DeviceTransportType,
deviceTransportTypeConfigurationInfoMap,
deviceTransportTypeHintMap,
deviceTransportTypeTranslationMap
} from '@shared/models/device.models';
@ -66,7 +65,6 @@ export class DeviceWizardDialogComponent extends
showNext = true;
createProfile = false;
createTransportConfiguration = false;
entityType = EntityType;
@ -88,7 +86,7 @@ export class DeviceWizardDialogComponent extends
customerFormGroup: FormGroup;
labelPosition = 'end';
labelPosition: MatHorizontalStepper['labelPosition'] = 'end';
serviceType = ServiceType.TB_RULE_ENGINE;
@ -109,7 +107,6 @@ export class DeviceWizardDialogComponent extends
label: [''],
gateway: [false],
overwriteActivityTime: [false],
transportType: [DeviceTransportType.DEFAULT, Validators.required],
addProfileType: [0],
deviceProfileId: [null, Validators.required],
newDeviceProfileTitle: [{value: null, disabled: true}],
@ -130,7 +127,6 @@ export class DeviceWizardDialogComponent extends
this.deviceWizardFormGroup.get('defaultQueueName').disable();
this.deviceWizardFormGroup.updateValueAndValidity();
this.createProfile = false;
this.createTransportConfiguration = false;
} else {
this.deviceWizardFormGroup.get('deviceProfileId').setValidators(null);
this.deviceWizardFormGroup.get('deviceProfileId').disable();
@ -141,18 +137,18 @@ export class DeviceWizardDialogComponent extends
this.deviceWizardFormGroup.updateValueAndValidity();
this.createProfile = true;
this.createTransportConfiguration = this.deviceWizardFormGroup.get('transportType').value &&
deviceTransportTypeConfigurationInfoMap.get(this.deviceWizardFormGroup.get('transportType').value).hasProfileConfiguration;
}
}
));
this.transportConfigFormGroup = this.fb.group(
{
transportType: [DeviceTransportType.DEFAULT, Validators.required],
transportConfiguration: [createDeviceProfileTransportConfiguration(DeviceTransportType.DEFAULT), Validators.required]
}
);
this.subscriptions.push(this.deviceWizardFormGroup.get('transportType').valueChanges.subscribe((transportType) => {
this.subscriptions.push(this.transportConfigFormGroup.get('transportType').valueChanges.subscribe((transportType) => {
this.deviceProfileTransportTypeChanged(transportType);
}));
@ -229,8 +225,6 @@ export class DeviceWizardDialogComponent extends
if (index > 0) {
if (!this.createProfile) {
index += 3;
} else if (!this.createTransportConfiguration) {
index += 1;
}
}
switch (index) {
@ -256,8 +250,6 @@ export class DeviceWizardDialogComponent extends
private deviceProfileTransportTypeChanged(deviceTransportType: DeviceTransportType): void {
this.transportConfigFormGroup.patchValue(
{transportConfiguration: createDeviceProfileTransportConfiguration(deviceTransportType)});
this.createTransportConfiguration = this.createProfile && deviceTransportType &&
deviceTransportTypeConfigurationInfoMap.get(deviceTransportType).hasProfileConfiguration;
}
add(): void {
@ -281,7 +273,7 @@ export class DeviceWizardDialogComponent extends
const deviceProfile: DeviceProfile = {
name: this.deviceWizardFormGroup.get('newDeviceProfileTitle').value,
type: DeviceProfileType.DEFAULT,
transportType: this.deviceWizardFormGroup.get('transportType').value,
transportType: this.transportConfigFormGroup.get('transportType').value,
provisionType: deviceProvisionConfiguration.type,
provisionDeviceKey,
profileData: {

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save