diff --git a/application/src/main/data/upgrade/3.2.2/schema_update.sql b/application/src/main/data/upgrade/3.2.2/schema_update.sql index 5647c301cf..9e94caf1af 100644 --- a/application/src/main/data/upgrade/3.2.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.2.2/schema_update.sql @@ -79,6 +79,67 @@ 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), + 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), + callback_url_scheme varchar(255), + 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); diff --git a/application/src/main/java/org/thingsboard/server/config/CustomOAuth2AuthorizationRequestResolver.java b/application/src/main/java/org/thingsboard/server/config/CustomOAuth2AuthorizationRequestResolver.java index bbcb7d656a..bc93253a73 100644 --- a/application/src/main/java/org/thingsboard/server/config/CustomOAuth2AuthorizationRequestResolver.java +++ b/application/src/main/java/org/thingsboard/server/config/CustomOAuth2AuthorizationRequestResolver.java @@ -37,6 +37,8 @@ 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.utils.MiscUtils; import javax.servlet.http.HttpServletRequest; @@ -46,12 +48,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 +66,9 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza @Autowired private ClientRegistrationRepository clientRegistrationRepository; + @Autowired + private OAuth2Service oAuth2Service; + @Autowired(required = false) private OAuth2Configuration oauth2Configuration; @@ -71,7 +77,8 @@ 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); + return resolve(request, registrationId, redirectUriAction, appPackage); } @Override @@ -80,7 +87,8 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza return null; } String redirectUriAction = getAction(request, "authorize"); - return resolve(request, registrationId, redirectUriAction); + String appPackage = getAppPackage(request); + return resolve(request, registrationId, redirectUriAction, appPackage); } private String getAction(HttpServletRequest request, String defaultAction) { @@ -91,8 +99,12 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza return action; } + private String getAppPackage(HttpServletRequest request) { + return request.getParameter("pkg"); + } + @SuppressWarnings("deprecation") - private OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId, String redirectUriAction) { + private OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId, String redirectUriAction, String appPackage) { if (registrationId == null) { return null; } @@ -104,6 +116,14 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza Map attributes = new HashMap<>(); attributes.put(OAuth2ParameterNames.REGISTRATION_ID, clientRegistration.getRegistrationId()); + if (!StringUtils.isEmpty(appPackage)) { + String callbackUrlScheme = this.oAuth2Service.findCallbackUrlScheme(UUID.fromString(registrationId), appPackage); + if (StringUtils.isEmpty(callbackUrlScheme)) { + throw new IllegalArgumentException("Invalid package: " + appPackage + ". No package info found for Client Registration."); + } else { + attributes.put(TbOAuth2ParameterNames.CALLBACK_URL_SCHEME, callbackUrlScheme); + } + } OAuth2AuthorizationRequest.Builder builder; if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(clientRegistration.getAuthorizationGrantType())) { diff --git a/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java b/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java index 6591a1577a..349c6de672 100644 --- a/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java @@ -22,12 +22,13 @@ 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.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.dao.oauth2.OAuth2Configuration; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; @@ -49,7 +50,8 @@ public class OAuth2Controller extends BaseController { @RequestMapping(value = "/noauth/oauth2Clients", method = RequestMethod.POST) @ResponseBody - public List getOAuth2Clients(HttpServletRequest request) throws ThingsboardException { + public List getOAuth2Clients(HttpServletRequest request, + @RequestParam(required = false) String pkgName) throws ThingsboardException { try { if (log.isDebugEnabled()) { log.debug("Executing getOAuth2Clients: [{}][{}][{}]", request.getScheme(), request.getServerName(), request.getServerPort()); @@ -59,7 +61,7 @@ public class OAuth2Controller extends BaseController { log.debug("Header: {} {}", header, request.getHeader(header)); } } - return oAuth2Service.getOAuth2Clients(MiscUtils.getScheme(request), MiscUtils.getDomainNameAndPort(request)); + return oAuth2Service.getOAuth2Clients(MiscUtils.getScheme(request), MiscUtils.getDomainNameAndPort(request), pkgName); } catch (Exception e) { throw handleException(e); } @@ -68,10 +70,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 +82,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); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index b91c46417c..8c27417f90 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/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); + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java index 4f38cf7a23..3ff3534806 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java +++ b/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); diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/BasicOAuth2ClientMapper.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/BasicOAuth2ClientMapper.java index 940bf8ad0a..f5172b64e7 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/BasicOAuth2ClientMapper.java +++ b/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 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); } } diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CustomOAuth2ClientMapper.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CustomOAuth2ClientMapper.java index cb08bc9f96..65ebb384de 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CustomOAuth2ClientMapper.java +++ b/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) { diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/GithubOAuth2ClientMapper.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/GithubOAuth2ClientMapper.java index 8e41c4a747..d6260fe482 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/GithubOAuth2ClientMapper.java +++ b/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 githubMapperConfig = oAuth2Configuration.getGithubMapper(); String email = getEmail(githubMapperConfig.get(EMAIL_URL_KEY), providerAccessToken); Map 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) { diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/OAuth2ClientMapper.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/OAuth2ClientMapper.java index 965b34d8b0..280418d066 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/OAuth2ClientMapper.java +++ b/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); } diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java index b6345f1618..0e413b4f22 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java +++ b/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())); } } diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java index 72a6c65f7c..227d733ebd 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java +++ b/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())); } } diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/TbOAuth2ParameterNames.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/TbOAuth2ParameterNames.java new file mode 100644 index 0000000000..aa5b32f055 --- /dev/null +++ b/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"; + +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java index 3f9411d0aa..158c3911b4 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java @@ -16,20 +16,30 @@ 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.deprecated.OAuth2ClientRegistrationInfo; +import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientsParams; import java.util.List; import java.util.UUID; public interface OAuth2Service { - List getOAuth2Clients(String domainScheme, String domainName); + List getOAuth2Clients(String domainScheme, String domainName, String pkgName); + @Deprecated void saveOAuth2Params(OAuth2ClientsParams oauth2Params); + @Deprecated OAuth2ClientsParams findOAuth2Params(); - OAuth2ClientRegistrationInfo findClientRegistrationInfo(UUID id); + void saveOAuth2Info(OAuth2Info oauth2Info); - List findAllClientRegistrationInfos(); + OAuth2Info findOAuth2Info(); + + OAuth2Registration findRegistration(UUID id); + + List findAllRegistrations(); + + String findCallbackUrlScheme(UUID registrationId, String pkgName); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2DomainId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2DomainId.java new file mode 100644 index 0000000000..220232f16d --- /dev/null +++ b/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)); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2MobileId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2MobileId.java new file mode 100644 index 0000000000..934d1f72a6 --- /dev/null +++ b/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)); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ParamsId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ParamsId.java new file mode 100644 index 0000000000..3aa0c5bb3d --- /dev/null +++ b/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)); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2RegistrationId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2RegistrationId.java new file mode 100644 index 0000000000..0019ef1a04 --- /dev/null +++ b/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)); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ClientRegistrationId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/deprecated/OAuth2ClientRegistrationId.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ClientRegistrationId.java rename to common/data/src/main/java/org/thingsboard/server/common/data/id/deprecated/OAuth2ClientRegistrationId.java index 88d4245dc7..616fc3b29c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ClientRegistrationId.java +++ b/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 diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ClientRegistrationInfoId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/deprecated/OAuth2ClientRegistrationInfoId.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ClientRegistrationInfoId.java rename to common/data/src/main/java/org/thingsboard/server/common/data/id/deprecated/OAuth2ClientRegistrationInfoId.java index 2e34eaf5ac..6ba959318c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ClientRegistrationInfoId.java +++ b/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 diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java index f75fb2aaa7..b46f23484f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationTemplate.java +++ b/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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Domain.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Domain.java new file mode 100644 index 0000000000..0dee447023 --- /dev/null +++ b/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 { + + 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; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2DomainInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2DomainInfo.java new file mode 100644 index 0000000000..9d9bd939da --- /dev/null +++ b/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; +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java new file mode 100644 index 0000000000..72f4b06161 --- /dev/null +++ b/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 oauth2ParamsInfos; +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Mobile.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Mobile.java new file mode 100644 index 0000000000..b3249a1ed5 --- /dev/null +++ b/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 { + + private OAuth2ParamsId oauth2ParamsId; + private String pkgName; + private String callbackUrlScheme; + + public OAuth2Mobile(OAuth2Mobile mobile) { + super(mobile); + this.oauth2ParamsId = mobile.oauth2ParamsId; + this.pkgName = mobile.pkgName; + this.callbackUrlScheme = mobile.callbackUrlScheme; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MobileInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MobileInfo.java new file mode 100644 index 0000000000..18fbd49dcd --- /dev/null +++ b/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 callbackUrlScheme; +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Params.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Params.java new file mode 100644 index 0000000000..570fe6cb20 --- /dev/null +++ b/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 { + + private boolean enabled; + private TenantId tenantId; + + public OAuth2Params(OAuth2Params oauth2Params) { + super(oauth2Params); + this.enabled = oauth2Params.enabled; + this.tenantId = oauth2Params.tenantId; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ParamsInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ParamsInfo.java new file mode 100644 index 0000000000..1a1d729d6b --- /dev/null +++ b/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 domainInfos; + private List mobileInfos; + private List clientRegistrations; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Registration.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Registration.java new file mode 100644 index 0000000000..5120e3202f --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Registration.java @@ -0,0 +1,77 @@ +/** + * 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 implements HasName { + + private OAuth2ParamsId oauth2ParamsId; + private OAuth2MapperConfig mapperConfig; + private String clientId; + private String clientSecret; + private String authorizationUri; + private String accessTokenUri; + private List scope; + private String userInfoUri; + private String userNameAttributeName; + private String jwkSetUri; + private String clientAuthenticationMethod; + private String loginButtonLabel; + private String loginButtonIcon; + + 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; + } + + @Override + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public String getName() { + return loginButtonLabel; + } + + @Override + public String getSearchText() { + return getName(); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/ClientRegistrationDto.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2RegistrationInfo.java similarity index 92% rename from common/data/src/main/java/org/thingsboard/server/common/data/oauth2/ClientRegistrationDto.java rename to common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2RegistrationInfo.java index 2598013ab6..449977f106 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/ClientRegistrationDto.java +++ b/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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/ClientRegistrationDto.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/ClientRegistrationDto.java new file mode 100644 index 0000000000..4f491a2d8a --- /dev/null +++ b/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 scope; + private String userInfoUri; + private String userNameAttributeName; + private String jwkSetUri; + private String clientAuthenticationMethod; + private String loginButtonLabel; + private String loginButtonIcon; + private JsonNode additionalInfo; +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/DomainInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/DomainInfo.java similarity index 85% rename from common/data/src/main/java/org/thingsboard/server/common/data/oauth2/DomainInfo.java rename to common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/DomainInfo.java index fd6b93100c..5078c4483f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/DomainInfo.java +++ b/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 diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/ExtendedOAuth2ClientRegistrationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/ExtendedOAuth2ClientRegistrationInfo.java similarity index 85% rename from common/data/src/main/java/org/thingsboard/server/common/data/oauth2/ExtendedOAuth2ClientRegistrationInfo.java rename to common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/ExtendedOAuth2ClientRegistrationInfo.java index 83647283a0..d071a6f1d4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/ExtendedOAuth2ClientRegistrationInfo.java +++ b/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 { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistration.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientRegistration.java similarity index 81% rename from common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistration.java rename to common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientRegistration.java index d0fa6648c8..cfac2de329 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistration.java +++ b/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 diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientRegistrationInfo.java similarity index 92% rename from common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationInfo.java rename to common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientRegistrationInfo.java index f70000693c..a99f56689b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistrationInfo.java +++ b/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"}) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientsDomainParams.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientsDomainParams.java similarity index 92% rename from common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientsDomainParams.java rename to common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientsDomainParams.java index 1570f71107..ff17fe2819 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientsDomainParams.java +++ b/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 diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientsParams.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientsParams.java similarity index 92% rename from common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientsParams.java rename to common/data/src/main/java/org/thingsboard/server/common/data/oauth2/deprecated/OAuth2ClientsParams.java index 57c7351295..4f7735ef04 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientsParams.java +++ b/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 diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index bfb530dd35..02c8db42d4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/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_CALLBACK_URL_SCHEME_PROPERTY = "callback_url_scheme"; + 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,7 +432,6 @@ 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_USER_INFO_URI_PROPERTY = "user_info_uri"; public static final String OAUTH2_USER_NAME_ATTRIBUTE_NAME_PROPERTY = "user_name_attribute_name"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2DomainEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2DomainEntity.java new file mode 100644 index 0000000000..f1dbe6fff7 --- /dev/null +++ b/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 { + + @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; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2MobileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2MobileEntity.java new file mode 100644 index 0000000000..403f7af958 --- /dev/null +++ b/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 { + + @Column(name = ModelConstants.OAUTH2_PARAMS_ID_PROPERTY) + private UUID oauth2ParamsId; + + @Column(name = ModelConstants.OAUTH2_PKG_NAME_PROPERTY) + private String pkgName; + + @Column(name = ModelConstants.OAUTH2_CALLBACK_URL_SCHEME_PROPERTY) + private String callbackUrlScheme; + + 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.callbackUrlScheme = mobile.getCallbackUrlScheme(); + } + + @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.setCallbackUrlScheme(callbackUrlScheme); + return mobile; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ParamsEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ParamsEntity.java new file mode 100644 index 0000000000..f2c893f6f3 --- /dev/null +++ b/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 { + + @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; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2RegistrationEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2RegistrationEntity.java new file mode 100644 index 0000000000..9c6c260316 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2RegistrationEntity.java @@ -0,0 +1,212 @@ +/** + * 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 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.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.UUID; + +@Data +@EqualsAndHashCode(callSuper = true) +@Entity +@TypeDef(name = "json", typeClass = JsonStringType.class) +@Table(name = ModelConstants.OAUTH2_REGISTRATION_COLUMN_FAMILY_NAME) +public class OAuth2RegistrationEntity extends BaseSqlEntity { + + @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_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.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.setUserInfoUri(userInfoUri); + registration.setUserNameAttributeName(userNameAttributeName); + registration.setJwkSetUri(jwkSetUri); + registration.setClientAuthenticationMethod(clientAuthenticationMethod); + registration.setLoginButtonLabel(loginButtonLabel); + registration.setLoginButtonIcon(loginButtonIcon); + return registration; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractOAuth2ClientRegistrationInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/AbstractOAuth2ClientRegistrationInfoEntity.java similarity index 97% rename from dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractOAuth2ClientRegistrationInfoEntity.java rename to dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/AbstractOAuth2ClientRegistrationInfoEntity.java index 4799087457..616f128920 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractOAuth2ClientRegistrationInfoEntity.java +++ b/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) diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/ExtendedOAuth2ClientRegistrationInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/ExtendedOAuth2ClientRegistrationInfoEntity.java similarity index 91% rename from dao/src/main/java/org/thingsboard/server/dao/model/sql/ExtendedOAuth2ClientRegistrationInfoEntity.java rename to dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/ExtendedOAuth2ClientRegistrationInfoEntity.java index 129bcf730b..beb525e2e0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/ExtendedOAuth2ClientRegistrationInfoEntity.java +++ b/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 { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ClientRegistrationEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/OAuth2ClientRegistrationEntity.java similarity index 89% rename from dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ClientRegistrationEntity.java rename to dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/OAuth2ClientRegistrationEntity.java index 505f2facf1..9de0b9daea 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ClientRegistrationEntity.java +++ b/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 diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ClientRegistrationInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/OAuth2ClientRegistrationInfoEntity.java similarity index 91% rename from dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ClientRegistrationInfoEntity.java rename to dao/src/main/java/org/thingsboard/server/dao/model/sql/deprecated/OAuth2ClientRegistrationInfoEntity.java index 1a379baf23..fbb9ec3fca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ClientRegistrationInfoEntity.java +++ b/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 diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/HybridClientRegistrationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/HybridClientRegistrationRepository.java index 7361dc21d2..feba5c0158 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/HybridClientRegistrationRepository.java +++ b/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(); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2DomainDao.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2DomainDao.java new file mode 100644 index 0000000000..78c237d943 --- /dev/null +++ b/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 { + + List findByOAuth2ParamsId(UUID oauth2ParamsId); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2MobileDao.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2MobileDao.java new file mode 100644 index 0000000000..3bccb61b0b --- /dev/null +++ b/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 { + + List findByOAuth2ParamsId(UUID oauth2ParamsId); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ParamsDao.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ParamsDao.java new file mode 100644 index 0000000000..5821431444 --- /dev/null +++ b/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 { + void deleteAll(); +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2RegistrationDao.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2RegistrationDao.java new file mode 100644 index 0000000000..ad12b12e48 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2RegistrationDao.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.dao.oauth2; + +import org.thingsboard.server.common.data.oauth2.OAuth2Registration; +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 { + + List findEnabledByDomainSchemesDomainNameAndPkgName(List domainSchemes, String domainName, String pkgName); + + List findByOAuth2ParamsId(UUID oauth2ParamsId); + + String findCallbackUrlScheme(UUID id, String pkgName); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java index acde25f8ed..8d06adee0b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java @@ -19,11 +19,21 @@ 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.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.*; @@ -45,9 +55,17 @@ 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 getOAuth2Clients(String domainSchemeStr, String domainName) { + public List getOAuth2Clients(String domainSchemeStr, String domainName, String pkgName) { log.trace("Executing getOAuth2Clients [{}://{}]", domainSchemeStr, domainName); if (domainSchemeStr == null) { throw new IncorrectParameterException(INCORRECT_DOMAIN_SCHEME); @@ -59,12 +77,12 @@ 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.findEnabledByDomainSchemesDomainNameAndPkgName(Arrays.asList(domainScheme, SchemeType.MIXED), domainName, pkgName).stream() .map(OAuth2Utils::toClientInfo) .collect(Collectors.toList()); } + @Deprecated @Override @Transactional public void saveOAuth2Params(OAuth2ClientsParams oauth2Params) { @@ -85,6 +103,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 +138,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 oauth2ParamsList = oauth2ParamsDao.find(TenantId.SYS_TENANT_ID); + oauth2Info.setEnabled(oauth2ParamsList.stream().anyMatch(param -> param.isEnabled())); + List oauth2ParamsInfos = new ArrayList<>(); + oauth2Info.setOauth2ParamsInfos(oauth2ParamsInfos); + oauth2ParamsList.stream().sorted(Comparator.comparing(BaseData::getUuidId)).forEach(oauth2Params -> { + List registrations = oauth2RegistrationDao.findByOAuth2ParamsId(oauth2Params.getId().getId()); + List domains = oauth2DomainDao.findByOAuth2ParamsId(oauth2Params.getId().getId()); + List 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 findCallbackUrlScheme(UUID id, String pkgName) { + log.trace("Executing findCallbackUrlScheme [{}][{}]", id, pkgName); validateId(id, INCORRECT_CLIENT_REGISTRATION_ID + id); - return clientRegistrationInfoDao.findById(null, id); + validateString(pkgName, "Incorrect package name"); + return oauth2RegistrationDao.findCallbackUrlScheme(id, pkgName); } + @Override - public List findAllClientRegistrationInfos() { - log.trace("Executing findAllClientRegistrationInfos"); - return clientRegistrationInfoDao.findAll(); + public List findAllRegistrations() { + log.trace("Executing findAllRegistrations"); + return oauth2RegistrationDao.find(TenantId.SYS_TENANT_ID); } private final Consumer clientParamsValidator = oauth2Params -> { @@ -212,4 +283,136 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se } } }; + + private final Consumer 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.getCallbackUrlScheme())) { + throw new DataValidationException("Callback URL scheme should be specified!"); + } + } + 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!"); + } + } + } + } + }; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java index 2a59ccb829..dd128b435b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java +++ b/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,127 @@ public class OAuth2Utils { clientRegistration.setDomainScheme(domainScheme); return clientRegistration; } + + public static OAuth2ParamsInfo toOAuth2ParamsInfo(List registrations, List domains, List 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()) + .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()) + .callbackUrlScheme(mobile.getCallbackUrlScheme()) + .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.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.setCallbackUrlScheme(mobileInfo.getCallbackUrlScheme()); + 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()) + .build(); + } + + private static OAuth2DomainInfo domainInfoToOAuth2DomainInfo(DomainInfo domainInfo) { + return OAuth2DomainInfo.builder() + .name(domainInfo.getName()) + .scheme(domainInfo.getScheme()) + .build(); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientRegistrationDao.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/deprecated/OAuth2ClientRegistrationDao.java similarity index 83% rename from dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientRegistrationDao.java rename to dao/src/main/java/org/thingsboard/server/dao/oauth2/deprecated/OAuth2ClientRegistrationDao.java index 2f4f2c1be2..63b2c46034 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientRegistrationDao.java +++ b/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 { void deleteAll(); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientRegistrationInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/deprecated/OAuth2ClientRegistrationInfoDao.java similarity index 81% rename from dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientRegistrationInfoDao.java rename to dao/src/main/java/org/thingsboard/server/dao/oauth2/deprecated/OAuth2ClientRegistrationInfoDao.java index 6fe93bacf4..9f44335602 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientRegistrationInfoDao.java +++ b/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 { List findAll(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2DomainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2DomainDao.java new file mode 100644 index 0000000000..0d74821678 --- /dev/null +++ b/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 implements OAuth2DomainDao { + + private final OAuth2DomainRepository repository; + + @Override + protected Class getEntityClass() { + return OAuth2DomainEntity.class; + } + + @Override + protected CrudRepository getCrudRepository() { + return repository; + } + + @Override + public List findByOAuth2ParamsId(UUID oauth2ParamsId) { + return DaoUtil.convertDataList(repository.findByOauth2ParamsId(oauth2ParamsId)); + } + +} + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2MobileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2MobileDao.java new file mode 100644 index 0000000000..6f216b23f2 --- /dev/null +++ b/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 implements OAuth2MobileDao { + + private final OAuth2MobileRepository repository; + + @Override + protected Class getEntityClass() { + return OAuth2MobileEntity.class; + } + + @Override + protected CrudRepository getCrudRepository() { + return repository; + } + + @Override + public List findByOAuth2ParamsId(UUID oauth2ParamsId) { + return DaoUtil.convertDataList(repository.findByOauth2ParamsId(oauth2ParamsId)); + } + +} + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ParamsDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ParamsDao.java new file mode 100644 index 0000000000..2f28cb58f6 --- /dev/null +++ b/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 implements OAuth2ParamsDao { + private final OAuth2ParamsRepository repository; + + @Override + protected Class getEntityClass() { + return OAuth2ParamsEntity.class; + } + + @Override + protected CrudRepository getCrudRepository() { + return repository; + } + + @Override + public void deleteAll() { + repository.deleteAll(); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2RegistrationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2RegistrationDao.java new file mode 100644 index 0000000000..c3ee8a8c03 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2RegistrationDao.java @@ -0,0 +1,62 @@ +/** + * 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.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 implements OAuth2RegistrationDao { + + private final OAuth2RegistrationRepository repository; + + @Override + protected Class getEntityClass() { + return OAuth2RegistrationEntity.class; + } + + @Override + protected CrudRepository getCrudRepository() { + return repository; + } + + @Override + public List findEnabledByDomainSchemesDomainNameAndPkgName(List domainSchemes, String domainName, String pkgName) { + return DaoUtil.convertDataList(repository.findAllEnabledByDomainSchemesNameAndPkgName(domainSchemes, domainName, pkgName)); + } + + @Override + public List findByOAuth2ParamsId(UUID oauth2ParamsId) { + return DaoUtil.convertDataList(repository.findByOauth2ParamsId(oauth2ParamsId)); + } + + @Override + public String findCallbackUrlScheme(UUID id, String pkgName) { + return repository.findCallbackUrlScheme(id, pkgName); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2DomainRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2DomainRepository.java new file mode 100644 index 0000000000..26d084f613 --- /dev/null +++ b/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 { + + List findByOauth2ParamsId(UUID oauth2ParamsId); + +} + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2MobileRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2MobileRepository.java new file mode 100644 index 0000000000..d4660ef2ee --- /dev/null +++ b/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 { + + List findByOauth2ParamsId(UUID oauth2ParamsId); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ParamsRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ParamsRepository.java new file mode 100644 index 0000000000..8e53b34e31 --- /dev/null +++ b/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 { +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2RegistrationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2RegistrationRepository.java new file mode 100644 index 0000000000..676df8adcc --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2RegistrationRepository.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 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 { + + @Query("SELECT reg " + + "FROM OAuth2RegistrationEntity reg " + + "LEFT JOIN OAuth2ParamsEntity params on reg.oauth2ParamsId = params.id " + + "LEFT JOIN OAuth2DomainEntity domain on reg.oauth2ParamsId = domain.oauth2ParamsId " + + "LEFT JOIN OAuth2MobileEntity mobile on reg.oauth2ParamsId = mobile.oauth2ParamsId " + + "WHERE params.enabled = true " + + "AND domain.domainName = :domainName " + + "AND domain.domainScheme IN (:domainSchemes) " + + "AND (:pkgName IS NULL OR mobile.pkgName = :pkgName)") + List findAllEnabledByDomainSchemesNameAndPkgName(@Param("domainSchemes") List domainSchemes, + @Param("domainName") String domainName, + @Param("pkgName") String pkgName); + + List findByOauth2ParamsId(UUID oauth2ParamsId); + + @Query("SELECT mobile.callbackUrlScheme " + + "FROM OAuth2MobileEntity mobile " + + "LEFT JOIN OAuth2RegistrationEntity reg on mobile.oauth2ParamsId = reg.oauth2ParamsId " + + "WHERE reg.id = :registrationId " + + "AND mobile.pkgName = :pkgName") + String findCallbackUrlScheme(@Param("registrationId") UUID id, + @Param("pkgName") String pkgName); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/JpaOAuth2ClientRegistrationDao.java similarity index 82% rename from dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationDao.java rename to dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/JpaOAuth2ClientRegistrationDao.java index 8aea9c9c3f..8dfe92b18d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationDao.java +++ b/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 implements OAuth2ClientRegistrationDao { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/JpaOAuth2ClientRegistrationInfoDao.java similarity index 85% rename from dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationInfoDao.java rename to dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/JpaOAuth2ClientRegistrationInfoDao.java index 0a25678e16..d37ca981f2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/JpaOAuth2ClientRegistrationInfoDao.java +++ b/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 implements OAuth2ClientRegistrationInfoDao { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRegistrationInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/OAuth2ClientRegistrationInfoRepository.java similarity index 81% rename from dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRegistrationInfoRepository.java rename to dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/OAuth2ClientRegistrationInfoRepository.java index 18ac3be05a..73a2ca9bba 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRegistrationInfoRepository.java +++ b/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 { @Query("SELECT new OAuth2ClientRegistrationInfoEntity(cr_info) " + "FROM OAuth2ClientRegistrationInfoEntity cr_info " + @@ -34,7 +35,7 @@ public interface OAuth2ClientRegistrationInfoRepository extends CrudRepository findAllByDomainSchemesAndName(@Param("domainSchemes") List 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 findAllExtended(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRegistrationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/OAuth2ClientRegistrationRepository.java similarity index 83% rename from dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRegistrationRepository.java rename to dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/deprecated/OAuth2ClientRegistrationRepository.java index 1849f46514..1f4e4783ab 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRegistrationRepository.java +++ b/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 { } diff --git a/dao/src/main/resources/sql/schema-entities-hsql.sql b/dao/src/main/resources/sql/schema-entities-hsql.sql index 2c5113867a..0e7aec5c19 100644 --- a/dao/src/main/resources/sql/schema-entities-hsql.sql +++ b/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), @@ -404,15 +411,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), + callback_url_scheme varchar(255), + 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 +463,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, diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 3140ff83d6..377d140597 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/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), @@ -441,15 +448,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), + callback_url_scheme varchar(255), + 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 +500,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, diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOAuth2ServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOAuth2ServiceTest.java index ebfbfccd2a..fa79e32bea 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOAuth2ServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOAuth2ServiceTest.java @@ -16,208 +16,225 @@ package org.thingsboard.server.dao.service; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; 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.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 firstGroup = Lists.newArrayList( - validClientRegistrationDto(), - validClientRegistrationDto(), - validClientRegistrationDto(), - validClientRegistrationDto() + List firstGroup = Lists.newArrayList( + validRegistrationInfo(), + validRegistrationInfo(), + validRegistrationInfo(), + validRegistrationInfo() ); - List secondGroup = Lists.newArrayList( - validClientRegistrationDto(), - validClientRegistrationDto() + List secondGroup = Lists.newArrayList( + validRegistrationInfo(), + validRegistrationInfo() ); - List thirdGroup = Lists.newArrayList( - validClientRegistrationDto() + List 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 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 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 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 nonExistentDomainClients = oAuth2Service.getOAuth2Clients("http", "non-existent-domain"); + List nonExistentDomainClients = oAuth2Service.getOAuth2Clients("http", "non-existent-domain", null); Assert.assertTrue(nonExistentDomainClients.isEmpty()); - List firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain"); + List firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", null); Assert.assertEquals(firstGroupClientInfos.size(), firstDomainHttpClients.size()); firstGroupClientInfos.forEach(firstGroupClientInfo -> { Assert.assertTrue( @@ -227,10 +244,10 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { ); }); - List firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain"); + List firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain", null); Assert.assertTrue(firstDomainHttpsClients.isEmpty()); - List fourthDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "fourth-domain"); + List fourthDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "fourth-domain", null); Assert.assertEquals(secondGroupClientInfos.size(), fourthDomainHttpClients.size()); secondGroupClientInfos.forEach(secondGroupClientInfo -> { Assert.assertTrue( @@ -239,7 +256,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { && clientInfo.getName().equals(secondGroupClientInfo.getName())) ); }); - List fourthDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "fourth-domain"); + List fourthDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "fourth-domain", null); Assert.assertEquals(secondGroupClientInfos.size(), fourthDomainHttpsClients.size()); secondGroupClientInfos.forEach(secondGroupClientInfo -> { Assert.assertTrue( @@ -249,7 +266,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { ); }); - List secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain"); + List secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null); Assert.assertEquals(firstGroupClientInfos.size() + secondGroupClientInfos.size(), secondDomainHttpClients.size()); firstGroupClientInfos.forEach(firstGroupClientInfo -> { Assert.assertTrue( @@ -266,7 +283,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { ); }); - List secondDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "second-domain"); + List secondDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "second-domain", null); Assert.assertEquals(firstGroupClientInfos.size() + thirdGroupClientInfos.size(), secondDomainHttpsClients.size()); firstGroupClientInfos.forEach(firstGroupClientInfo -> { Assert.assertTrue( @@ -286,34 +303,35 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { @Test public void testGetOAuth2ClientsForHttpAndHttps() { - List firstGroup = Lists.newArrayList( - validClientRegistrationDto(), - validClientRegistrationDto(), - validClientRegistrationDto(), - validClientRegistrationDto() + List 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 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 firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain"); + List firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", null); Assert.assertEquals(firstGroupClientInfos.size(), firstDomainHttpClients.size()); firstGroupClientInfos.forEach(firstGroupClientInfo -> { Assert.assertTrue( @@ -323,7 +341,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest { ); }); - List firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain"); + List firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain", null); Assert.assertEquals(firstGroupClientInfos.size(), firstDomainHttpsClients.size()); firstGroupClientInfos.forEach(firstGroupClientInfo -> { Assert.assertTrue( @@ -336,166 +354,220 @@ 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 secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain"); + List secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null); Assert.assertEquals(5, secondDomainHttpClients.size()); - clientsParams.setEnabled(false); - oAuth2Service.saveOAuth2Params(clientsParams); + oAuth2Info.setEnabled(false); + oAuth2Service.saveOAuth2Info(oAuth2Info); - List secondDomainHttpDisabledClients = oAuth2Service.getOAuth2Clients("http", "second-domain"); + List secondDomainHttpDisabledClients = oAuth2Service.getOAuth2Clients("http", "second-domain", 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 foundClientRegistrationInfos = oAuth2Service.findAllClientRegistrationInfos(); - Assert.assertEquals(6, foundClientRegistrationInfos.size()); - clientsParams.getDomainsParams().stream() - .flatMap(domainParams -> domainParams.getClientRegistrations().stream()) - .forEach(clientRegistrationDto -> + oAuth2Service.saveOAuth2Info(oAuth2Info); + List 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 clientRegistrationInfos = oAuth2Service.findAllClientRegistrationInfos(); - clientRegistrationInfos.forEach(clientRegistrationInfo -> { - OAuth2ClientRegistrationInfo foundClientRegistrationInfo = oAuth2Service.findClientRegistrationInfo(clientRegistrationInfo.getUuidId()); - Assert.assertEquals(clientRegistrationInfo, foundClientRegistrationInfo); + oAuth2Service.saveOAuth2Info(oAuth2Info); + List 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 testFindCallbackUrlScheme() { + 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( + OAuth2MobileInfo.builder().pkgName("com.test.pkg1").callbackUrlScheme("testPkg1Callback").build(), + OAuth2MobileInfo.builder().pkgName("com.test.pkg2").callbackUrlScheme("testPkg2Callback").build() + )) + .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 firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", "com.test.pkg1"); + Assert.assertEquals(3, firstDomainHttpClients.size()); + for (OAuth2ClientInfo clientInfo : firstDomainHttpClients) { + String[] segments = clientInfo.getUrl().split("/"); + String registrationId = segments[segments.length-1]; + String callbackUrlScheme = oAuth2Service.findCallbackUrlScheme(UUID.fromString(registrationId), "com.test.pkg1"); + Assert.assertNotNull(callbackUrlScheme); + Assert.assertEquals("testPkg1Callback", callbackUrlScheme); + callbackUrlScheme = oAuth2Service.findCallbackUrlScheme(UUID.fromString(registrationId), "com.test.pkg2"); + Assert.assertNotNull(callbackUrlScheme); + Assert.assertEquals("testPkg2Callback", callbackUrlScheme); + callbackUrlScheme = oAuth2Service.findCallbackUrlScheme(UUID.fromString(registrationId), "com.test.pkg3"); + Assert.assertNull(callbackUrlScheme); + } + } + + private OAuth2Info createDefaultOAuth2Info() { + return 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(Lists.newArrayList( - validClientRegistrationDto(), - validClientRegistrationDto(), - validClientRegistrationDto(), - validClientRegistrationDto() + validRegistrationInfo(), + validRegistrationInfo(), + validRegistrationInfo(), + validRegistrationInfo() )) .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.MIXED).build(), + OAuth2DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build() )) + .mobileInfos(Collections.emptyList()) .clientRegistrations(Lists.newArrayList( - validClientRegistrationDto(), - validClientRegistrationDto() + validRegistrationInfo(), + validRegistrationInfo() )) .build() )); } - private ClientRegistrationDto validClientRegistrationDto() { - return ClientRegistrationDto.builder() + private OAuth2RegistrationInfo validRegistrationInfo() { + return OAuth2RegistrationInfo.builder() .clientId(UUID.randomUUID().toString()) .clientSecret(UUID.randomUUID().toString()) .authorizationUri(UUID.randomUUID().toString()) diff --git a/dao/src/test/resources/sql/hsql/drop-all-tables.sql b/dao/src/test/resources/sql/hsql/drop-all-tables.sql index 726b4ba412..f7b1b4118d 100644 --- a/dao/src/test/resources/sql/hsql/drop-all-tables.sql +++ b/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; diff --git a/dao/src/test/resources/sql/psql/drop-all-tables.sql b/dao/src/test/resources/sql/psql/drop-all-tables.sql index 855a53df2d..a29dea43c2 100644 --- a/dao/src/test/resources/sql/psql/drop-all-tables.sql +++ b/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; diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index 8ad95805a5..14a008634b 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/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 getOAuth2Clients() { + public List getOAuth2Clients(String pkgName) { + Map 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>() { - }).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() { diff --git a/ui-ngx/src/app/core/auth/auth.service.ts b/ui-ngx/src/app/core/auth/auth.service.ts index c17d993bf7..68724fa0dc 100644 --- a/ui-ngx/src/app/core/auth/auth.service.ts +++ b/ui-ngx/src/app/core/auth/auth.service.ts @@ -45,7 +45,7 @@ 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 { isDefinedAndNotNull, isMobileApp } from '@core/utils'; @Injectable({ providedIn: 'root' @@ -204,8 +204,12 @@ export class AuthService { } } - public loadOAuth2Clients(): Observable> { - return this.http.post>(`/api/noauth/oauth2Clients`, + public loadOAuth2Clients(pkgName?: string): Observable> { + let url = '/api/noauth/oauth2Clients'; + if (isDefinedAndNotNull(pkgName)) { + url += `?pkgName=${pkgName}`; + } + return this.http.post>(url, null, defaultHttpOptions()).pipe( catchError(err => of([])), tap((OAuth2Clients) => { diff --git a/ui-ngx/src/app/core/http/oauth2.service.ts b/ui-ngx/src/app/core/http/oauth2.service.ts index e81d472130..72a6bc77af 100644 --- a/ui-ngx/src/app/core/http/oauth2.service.ts +++ b/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 { - return this.http.get(`/api/oauth2/config`, defaultHttpOptionsFromConfig(config)); + public getOAuth2Settings(config?: RequestConfig): Observable { + return this.http.get(`/api/oauth2/config`, defaultHttpOptionsFromConfig(config)); } public getOAuth2Template(config?: RequestConfig): Observable> { return this.http.get>(`/api/oauth2/config/template`, defaultHttpOptionsFromConfig(config)); } - public saveOAuth2Settings(OAuth2Setting: OAuth2ClientsParams, config?: RequestConfig): Observable { - return this.http.post('/api/oauth2/config', OAuth2Setting, + public saveOAuth2Settings(OAuth2Setting: OAuth2Info, config?: RequestConfig): Observable { + return this.http.post('/api/oauth2/config', OAuth2Setting, defaultHttpOptionsFromConfig(config)); } diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html index 3998b4fc9a..3ea9a1ca11 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html @@ -34,19 +34,19 @@ {{ 'admin.oauth2.enable' | translate }}
- +
- + - {{ domainListTittle(domain) }} + {{ domainListTittle(oauth2ParamsInfo) }} + + + + + + + +
- - {{ 'admin.domain-name-unique' | translate }} - - -
- - admin.oauth2.redirect-uri-template - - - - - - - -
+
+
+ +
+ + + + +
+
+ admin.oauth2.no-mobile-apps +
+
+
+
+
+ + admin.oauth2.mobile-package + + + + {{ 'admin.oauth2.mobile-package-unique' | translate }} + +
+ + admin.oauth2.mobile-callback-url-scheme + + +
+
+ - +
- - -
-
+
+
- - -
- -
-
- + +
+ +
admin.oauth2.providers
- @@ -140,8 +190,8 @@ @@ -467,7 +517,7 @@ diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss index e17d7c34e4..aeb401dedf 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss @@ -62,7 +62,7 @@ } } } - .domains-list{ + .domains-list, .apps-list { margin-bottom: 1.5em; .mat-form-field-suffix .mat-icon-button .mat-icon{ font-size: 24px; diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts index e93ea168fe..39fb6ac6ff 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts @@ -18,8 +18,6 @@ import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, FormArray, FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms'; import { ClientAuthenticationMethod, - ClientRegistration, - DomainInfo, DomainSchema, domainSchemaTranslations, MapperConfig, @@ -27,8 +25,10 @@ import { MapperConfigCustom, MapperConfigType, OAuth2ClientRegistrationTemplate, - OAuth2ClientsDomainParams, - OAuth2ClientsParams, + OAuth2DomainInfo, + OAuth2Info, OAuth2MobileInfo, + OAuth2ParamsInfo, + OAuth2RegistrationInfo, TenantNameStrategy } from '@shared/models/oauth2.models'; import { Store } from '@ngrx/store'; @@ -52,6 +52,20 @@ import { ActivatedRoute } from '@angular/router'; }) export class OAuth2SettingsComponent extends PageComponent implements OnInit, HasConfirmForm, OnDestroy { + constructor(protected store: Store, + private route: ActivatedRoute, + private oauth2Service: OAuth2Service, + private fb: FormBuilder, + private dialogService: DialogService, + private translate: TranslateService, + @Inject(WINDOW) private window: Window) { + super(store); + } + + get oauth2ParamsInfos(): FormArray { + return this.oauth2SettingsForm.get('oauth2ParamsInfos') as FormArray; + } + private URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.,?+=&%@\-/]*)?$/; private DOMAIN_AND_PORT_REGEXP = /^(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?$/; private subscriptions: Subscription[] = []; @@ -77,7 +91,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha readonly separatorKeysCodes: number[] = [ENTER, COMMA]; oauth2SettingsForm: FormGroup; - auth2ClientsParams: OAuth2ClientsParams; + oauth2Info: OAuth2Info; clientAuthenticationMethods = Object.keys(ClientAuthenticationMethod); mapperConfigType = MapperConfigType; @@ -90,14 +104,14 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha private loginProcessingUrl: string = this.route.snapshot.data.loginProcessingUrl; - constructor(protected store: Store, - private route: ActivatedRoute, - private oauth2Service: OAuth2Service, - private fb: FormBuilder, - private dialogService: DialogService, - private translate: TranslateService, - @Inject(WINDOW) private window: Window) { - super(store); + private static validateScope(control: AbstractControl): ValidationErrors | null { + const scope: string[] = control.value; + if (!scope || !scope.length) { + return { + required: true + }; + } + return null; } ngOnInit(): void { @@ -106,10 +120,10 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha this.oauth2Service.getOAuth2Template(), this.oauth2Service.getOAuth2Settings() ]).subscribe( - ([templates, auth2ClientsParams]) => { + ([templates, oauth2Info]) => { this.initTemplates(templates); - this.auth2ClientsParams = auth2ClientsParams; - this.initOAuth2Settings(this.auth2ClientsParams); + this.oauth2Info = oauth2Info; + this.initOAuth2Settings(this.oauth2Info); } ); } @@ -130,11 +144,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha this.templateProvider.sort(); } - get domainsParams(): FormArray { - return this.oauth2SettingsForm.get('domainsParams') as FormArray; - } - - private formBasicGroup(type: MapperConfigType, mapperConfigBasic?: MapperConfigBasic): FormGroup { + private formBasicGroup(mapperConfigBasic?: MapperConfigBasic): FormGroup { let tenantNamePattern; if (mapperConfigBasic?.tenantNamePattern) { tenantNamePattern = mapperConfigBasic.tenantNamePattern; @@ -173,16 +183,16 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha private buildOAuth2SettingsForm(): void { this.oauth2SettingsForm = this.fb.group({ - domainsParams: this.fb.array([]), + oauth2ParamsInfos: this.fb.array([]), enabled: [false] }); } - private initOAuth2Settings(auth2ClientsParams: OAuth2ClientsParams): void { - if (auth2ClientsParams) { - this.oauth2SettingsForm.patchValue({enabled: auth2ClientsParams.enabled}, {emitEvent: false}); - auth2ClientsParams.domainsParams.forEach((domain) => { - this.domainsParams.push(this.buildDomainsForm(domain)); + private initOAuth2Settings(oauth2Info: OAuth2Info): void { + if (oauth2Info) { + this.oauth2SettingsForm.patchValue({enabled: oauth2Info.enabled}, {emitEvent: false}); + oauth2Info.oauth2ParamsInfos.forEach((oauth2ParamsInfo) => { + this.oauth2ParamsInfos.push(this.buildOAuth2ParamsInfoForm(oauth2ParamsInfo)); }); } } @@ -201,8 +211,20 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha return null; } + private uniquePkgNameValidator(control: FormGroup): { [key: string]: boolean } | null { + if (control.parent?.value) { + const pkgName = control.value.pkgName; + const mobileInfosList = control.parent.getRawValue() + .filter((mobileInfo) => mobileInfo.pkgName === pkgName); + if (mobileInfosList.length > 1) { + return {unique: true}; + } + } + return null; + } + public domainListTittle(control: AbstractControl): string { - const domainInfos = control.get('domainInfos').value as DomainInfo[]; + const domainInfos = control.get('domainInfos').value as OAuth2DomainInfo[]; if (domainInfos.length) { const domainList = new Set(); domainInfos.forEach((domain) => { @@ -213,41 +235,51 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha return this.translate.instant('admin.oauth2.new-domain'); } - private buildDomainsForm(auth2ClientsDomainParams?: OAuth2ClientsDomainParams): FormGroup { - const formDomain = this.fb.group({ + private buildOAuth2ParamsInfoForm(oauth2ParamsInfo?: OAuth2ParamsInfo): FormGroup { + const formOAuth2Params = this.fb.group({ domainInfos: this.fb.array([], Validators.required), + mobileInfos: this.fb.array([]), clientRegistrations: this.fb.array([], Validators.required) }); - if (auth2ClientsDomainParams) { - auth2ClientsDomainParams.domainInfos.forEach((domain) => { - this.clientDomainInfos(formDomain).push(this.buildDomainForm(domain)); + if (oauth2ParamsInfo) { + oauth2ParamsInfo.domainInfos.forEach((domain) => { + this.domainInfos(formOAuth2Params).push(this.buildDomainInfoForm(domain)); + }); + oauth2ParamsInfo.mobileInfos.forEach((mobile) => { + this.mobileInfos(formOAuth2Params).push(this.buildMobileInfoForm(mobile)); }); - auth2ClientsDomainParams.clientRegistrations.forEach((registration) => { - this.clientDomainProviders(formDomain).push(this.buildProviderForm(registration)); + oauth2ParamsInfo.clientRegistrations.forEach((registration) => { + this.clientRegistrations(formOAuth2Params).push(this.buildRegistrationForm(registration)); }); } else { - this.clientDomainProviders(formDomain).push(this.buildProviderForm()); - this.clientDomainInfos(formDomain).push(this.buildDomainForm()); + this.clientRegistrations(formOAuth2Params).push(this.buildRegistrationForm()); + this.domainInfos(formOAuth2Params).push(this.buildDomainInfoForm()); } - return formDomain; + return formOAuth2Params; } - private buildDomainForm(domainInfo?: DomainInfo): FormGroup { - const domain = this.fb.group({ + private buildDomainInfoForm(domainInfo?: OAuth2DomainInfo): FormGroup { + return this.fb.group({ name: [domainInfo ? domainInfo.name : this.window.location.hostname, [ Validators.required, Validators.pattern(this.DOMAIN_AND_PORT_REGEXP)]], scheme: [domainInfo?.scheme ? domainInfo.scheme : DomainSchema.HTTPS, Validators.required] }, {validators: this.uniqueDomainValidator}); - return domain; } - private buildProviderForm(clientRegistration?: ClientRegistration): FormGroup { + private buildMobileInfoForm(mobileInfo?: OAuth2MobileInfo): FormGroup { + return this.fb.group({ + pkgName: [mobileInfo?.pkgName, [Validators.required]], + callbackUrlScheme: [mobileInfo?.callbackUrlScheme, [Validators.required]], + }, {validators: this.uniquePkgNameValidator}); + } + + private buildRegistrationForm(registration?: OAuth2RegistrationInfo): FormGroup { let additionalInfo = null; - if (isDefinedAndNotNull(clientRegistration?.additionalInfo)) { - additionalInfo = clientRegistration.additionalInfo; + if (isDefinedAndNotNull(registration?.additionalInfo)) { + additionalInfo = registration.additionalInfo; if (this.templateProvider.indexOf(additionalInfo.providerName) === -1) { additionalInfo.providerName = 'Custom'; } @@ -261,43 +293,43 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha additionalInfo: this.fb.group({ providerName: [additionalInfo?.providerName ? additionalInfo?.providerName : defaultProviderName, Validators.required] }), - loginButtonLabel: [clientRegistration?.loginButtonLabel ? clientRegistration.loginButtonLabel : null, Validators.required], - loginButtonIcon: [clientRegistration?.loginButtonIcon ? clientRegistration.loginButtonIcon : null], - clientId: [clientRegistration?.clientId ? clientRegistration.clientId : '', Validators.required], - clientSecret: [clientRegistration?.clientSecret ? clientRegistration.clientSecret : '', Validators.required], - accessTokenUri: [clientRegistration?.accessTokenUri ? clientRegistration.accessTokenUri : '', + loginButtonLabel: [registration?.loginButtonLabel ? registration.loginButtonLabel : null, Validators.required], + loginButtonIcon: [registration?.loginButtonIcon ? registration.loginButtonIcon : null], + clientId: [registration?.clientId ? registration.clientId : '', Validators.required], + clientSecret: [registration?.clientSecret ? registration.clientSecret : '', Validators.required], + accessTokenUri: [registration?.accessTokenUri ? registration.accessTokenUri : '', [Validators.required, Validators.pattern(this.URL_REGEXP)]], - authorizationUri: [clientRegistration?.authorizationUri ? clientRegistration.authorizationUri : '', + authorizationUri: [registration?.authorizationUri ? registration.authorizationUri : '', [Validators.required, Validators.pattern(this.URL_REGEXP)]], - scope: this.fb.array(clientRegistration?.scope ? clientRegistration.scope : [], this.validateScope), - jwkSetUri: [clientRegistration?.jwkSetUri ? clientRegistration.jwkSetUri : '', Validators.pattern(this.URL_REGEXP)], - userInfoUri: [clientRegistration?.userInfoUri ? clientRegistration.userInfoUri : '', + scope: this.fb.array(registration?.scope ? registration.scope : [], OAuth2SettingsComponent.validateScope), + jwkSetUri: [registration?.jwkSetUri ? registration.jwkSetUri : '', Validators.pattern(this.URL_REGEXP)], + userInfoUri: [registration?.userInfoUri ? registration.userInfoUri : '', [Validators.required, Validators.pattern(this.URL_REGEXP)]], clientAuthenticationMethod: [ - clientRegistration?.clientAuthenticationMethod ? clientRegistration.clientAuthenticationMethod : ClientAuthenticationMethod.POST, + registration?.clientAuthenticationMethod ? registration.clientAuthenticationMethod : ClientAuthenticationMethod.POST, Validators.required], userNameAttributeName: [ - clientRegistration?.userNameAttributeName ? clientRegistration.userNameAttributeName : 'email', Validators.required], + registration?.userNameAttributeName ? registration.userNameAttributeName : 'email', Validators.required], mapperConfig: this.fb.group({ allowUserCreation: [ - isDefinedAndNotNull(clientRegistration?.mapperConfig?.allowUserCreation) ? - clientRegistration.mapperConfig.allowUserCreation : true + isDefinedAndNotNull(registration?.mapperConfig?.allowUserCreation) ? + registration.mapperConfig.allowUserCreation : true ], activateUser: [ - isDefinedAndNotNull(clientRegistration?.mapperConfig?.activateUser) ? clientRegistration.mapperConfig.activateUser : false + isDefinedAndNotNull(registration?.mapperConfig?.activateUser) ? registration.mapperConfig.activateUser : false ], type: [ - clientRegistration?.mapperConfig?.type ? clientRegistration.mapperConfig.type : MapperConfigType.BASIC, Validators.required + registration?.mapperConfig?.type ? registration.mapperConfig.type : MapperConfigType.BASIC, Validators.required ] } ) }); - if (clientRegistration) { - this.changeMapperConfigType(clientRegistrationFormGroup, clientRegistration.mapperConfig.type, clientRegistration.mapperConfig); + if (registration) { + this.changeMapperConfigType(clientRegistrationFormGroup, registration.mapperConfig.type, registration.mapperConfig); } else { this.changeMapperConfigType(clientRegistrationFormGroup, MapperConfigType.BASIC); this.setProviderDefaultValue(defaultProviderName, clientRegistrationFormGroup); @@ -315,16 +347,6 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha return clientRegistrationFormGroup; } - private validateScope(control: AbstractControl): ValidationErrors | null { - const scope: string[] = control.value; - if (!scope || !scope.length) { - return { - required: true - }; - } - return null; - } - private setProviderDefaultValue(provider: string, clientRegistration: FormGroup) { if (provider === 'Custom') { clientRegistration.reset(this.defaultProvider, {emitEvent: false}); @@ -355,7 +377,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha } else { mapperConfig.removeControl('custom'); if (!mapperConfig.get('basic')) { - mapperConfig.addControl('basic', this.formBasicGroup(type, predefinedValue?.basic)); + mapperConfig.addControl('basic', this.formBasicGroup(predefinedValue?.basic)); } if (type === MapperConfigType.GITHUB) { mapperConfig.get('basic.emailAttributeKey').disable(); @@ -370,7 +392,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha const setting = this.oauth2SettingsForm.getRawValue(); this.oauth2Service.saveOAuth2Settings(setting).subscribe( (oauth2Settings) => { - this.auth2ClientsParams = oauth2Settings; + this.oauth2Info = oauth2Settings; this.oauth2SettingsForm.patchValue(this.oauth2SettingsForm, {emitEvent: false}); this.oauth2SettingsForm.markAsUntouched(); this.oauth2SettingsForm.markAsPristine(); @@ -403,58 +425,62 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha controller.markAsDirty(); } - addDomain(): void { - this.domainsParams.push(this.buildDomainsForm()); + addOAuth2ParamsInfo(): void { + this.oauth2ParamsInfos.push(this.buildOAuth2ParamsInfoForm()); } - deleteDomain($event: Event, index: number): void { + deleteOAuth2ParamsInfo($event: Event, index: number): void { if ($event) { $event.stopPropagation(); $event.preventDefault(); } - const domainName = this.domainListTittle(this.domainsParams.at(index)); + const domainName = this.domainListTittle(this.oauth2ParamsInfos.at(index)); this.dialogService.confirm( this.translate.instant('admin.oauth2.delete-domain-title', {domainName: domainName || ''}), this.translate.instant('admin.oauth2.delete-domain-text'), null, this.translate.instant('action.delete') ).subscribe((data) => { if (data) { - this.domainsParams.removeAt(index); - this.domainsParams.markAsTouched(); - this.domainsParams.markAsDirty(); + this.oauth2ParamsInfos.removeAt(index); + this.oauth2ParamsInfos.markAsTouched(); + this.oauth2ParamsInfos.markAsDirty(); } }); } - clientDomainProviders(control: AbstractControl): FormArray { + clientRegistrations(control: AbstractControl): FormArray { return control.get('clientRegistrations') as FormArray; } - clientDomainInfos(control: AbstractControl): FormArray { + domainInfos(control: AbstractControl): FormArray { return control.get('domainInfos') as FormArray; } - addProvider(control: AbstractControl): void { - this.clientDomainProviders(control).push(this.buildProviderForm()); + mobileInfos(control: AbstractControl): FormArray { + return control.get('mobileInfos') as FormArray; } - deleteProvider($event: Event, control: AbstractControl, index: number): void { + addRegistration(control: AbstractControl): void { + this.clientRegistrations(control).push(this.buildRegistrationForm()); + } + + deleteRegistration($event: Event, control: AbstractControl, index: number): void { if ($event) { $event.stopPropagation(); $event.preventDefault(); } - const providerName = this.clientDomainProviders(control).at(index).get('additionalInfo.providerName').value; + const providerName = this.clientRegistrations(control).at(index).get('additionalInfo.providerName').value; this.dialogService.confirm( this.translate.instant('admin.oauth2.delete-registration-title', {name: providerName || ''}), this.translate.instant('admin.oauth2.delete-registration-text'), null, this.translate.instant('action.delete') ).subscribe((data) => { if (data) { - this.clientDomainProviders(control).removeAt(index); - this.clientDomainProviders(control).markAsTouched(); - this.clientDomainProviders(control).markAsDirty(); + this.clientRegistrations(control).removeAt(index); + this.clientRegistrations(control).markAsTouched(); + this.clientRegistrations(control).markAsDirty(); } }); } @@ -480,24 +506,41 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha } addDomainInfo(control: AbstractControl): void { - this.clientDomainInfos(control).push(this.buildDomainForm({ + this.domainInfos(control).push(this.buildDomainInfoForm({ name: '', scheme: DomainSchema.HTTPS })); } - removeDomain($event: Event, control: AbstractControl, index: number): void { + removeDomainInfo($event: Event, control: AbstractControl, index: number): void { + if ($event) { + $event.stopPropagation(); + $event.preventDefault(); + } + this.domainInfos(control).removeAt(index); + this.domainInfos(control).markAsTouched(); + this.domainInfos(control).markAsDirty(); + } + + addMobileInfo(control: AbstractControl): void { + this.mobileInfos(control).push(this.buildMobileInfoForm({ + pkgName: '', + callbackUrlScheme: '' + })); + } + + removeMobileInfo($event: Event, control: AbstractControl, index: number): void { if ($event) { $event.stopPropagation(); $event.preventDefault(); } - this.clientDomainInfos(control).removeAt(index); - this.clientDomainInfos(control).markAsTouched(); - this.clientDomainInfos(control).markAsDirty(); + this.mobileInfos(control).removeAt(index); + this.mobileInfos(control).markAsTouched(); + this.mobileInfos(control).markAsDirty(); } redirectURI(control: AbstractControl, schema?: DomainSchema): string { - const domainInfo = control.value as DomainInfo; + const domainInfo = control.value as OAuth2DomainInfo; if (domainInfo.name !== '') { let protocol; if (isDefined(schema)) { diff --git a/ui-ngx/src/app/shared/models/oauth2.models.ts b/ui-ngx/src/app/shared/models/oauth2.models.ts index 08ff402502..93b147c887 100644 --- a/ui-ngx/src/app/shared/models/oauth2.models.ts +++ b/ui-ngx/src/app/shared/models/oauth2.models.ts @@ -16,21 +16,27 @@ import { HasUUID } from '@shared/models/id/has-uuid'; -export interface OAuth2ClientsParams { +export interface OAuth2Info { enabled: boolean; - domainsParams: OAuth2ClientsDomainParams[]; + oauth2ParamsInfos: OAuth2ParamsInfo[]; } -export interface OAuth2ClientsDomainParams { - clientRegistrations: ClientRegistration[]; - domainInfos: DomainInfo[]; +export interface OAuth2ParamsInfo { + clientRegistrations: OAuth2RegistrationInfo[]; + domainInfos: OAuth2DomainInfo[]; + mobileInfos: OAuth2MobileInfo[]; } -export interface DomainInfo { +export interface OAuth2DomainInfo { name: string; scheme: DomainSchema; } +export interface OAuth2MobileInfo { + pkgName: string; + callbackUrlScheme: string; +} + export enum DomainSchema{ HTTP = 'HTTP', HTTPS = 'HTTPS', @@ -57,7 +63,7 @@ export enum TenantNameStrategy{ CUSTOM = 'CUSTOM' } -export interface OAuth2ClientRegistrationTemplate extends ClientRegistration{ +export interface OAuth2ClientRegistrationTemplate extends OAuth2RegistrationInfo{ comment: string; createdTime: number; helpLink: string; @@ -66,7 +72,7 @@ export interface OAuth2ClientRegistrationTemplate extends ClientRegistration{ id: HasUUID; } -export interface ClientRegistration { +export interface OAuth2RegistrationInfo { loginButtonLabel: string; loginButtonIcon: string; clientId: string; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index aabd4207d8..5fbb6ed3fb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -219,7 +219,16 @@ "domain-schema-http": "HTTP", "domain-schema-https": "HTTPS", "domain-schema-mixed": "HTTP+HTTPS", - "enable": "Enable OAuth2 settings" + "enable": "Enable OAuth2 settings", + "domains": "Domains", + "mobile-apps": "Mobile applications", + "no-mobile-apps": "No applications configured", + "mobile-package": "Application package", + "mobile-package-unique": "Application package must be unique.", + "mobile-callback-url-scheme": "Callback URL scheme", + "add-mobile-app": "Add application", + "delete-mobile-app": "Delete application info", + "providers": "Providers" } }, "alarm": {