Commit cc531daaeee9f4ff2f38b3f2dcaa25f5854358a6

Authored by Igor Kulikov
1 parent 8e4f8594

Add platform type filter for oauth2 registrations.

Showing 22 changed files with 187 additions and 44 deletions
... ... @@ -96,6 +96,7 @@ CREATE TABLE IF NOT EXISTS oauth2_registration (
96 96 authorization_uri varchar(255),
97 97 token_uri varchar(255),
98 98 scope varchar(255),
  99 + platforms varchar(255),
99 100 user_info_uri varchar(255),
100 101 user_name_attribute_name varchar(255),
101 102 jwk_set_uri varchar(255),
... ...
... ... @@ -26,9 +26,11 @@ import org.springframework.web.bind.annotation.RequestParam;
26 26 import org.springframework.web.bind.annotation.ResponseBody;
27 27 import org.springframework.web.bind.annotation.ResponseStatus;
28 28 import org.springframework.web.bind.annotation.RestController;
  29 +import org.thingsboard.server.common.data.StringUtils;
29 30 import org.thingsboard.server.common.data.exception.ThingsboardException;
30 31 import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo;
31 32 import org.thingsboard.server.common.data.oauth2.OAuth2Info;
  33 +import org.thingsboard.server.common.data.oauth2.PlatformType;
32 34 import org.thingsboard.server.dao.oauth2.OAuth2Configuration;
33 35 import org.thingsboard.server.queue.util.TbCoreComponent;
34 36 import org.thingsboard.server.service.security.permission.Operation;
... ... @@ -51,7 +53,8 @@ public class OAuth2Controller extends BaseController {
51 53 @RequestMapping(value = "/noauth/oauth2Clients", method = RequestMethod.POST)
52 54 @ResponseBody
53 55 public List<OAuth2ClientInfo> getOAuth2Clients(HttpServletRequest request,
54   - @RequestParam(required = false) String pkgName) throws ThingsboardException {
  56 + @RequestParam(required = false) String pkgName,
  57 + @RequestParam(required = false) String platform) throws ThingsboardException {
55 58 try {
56 59 if (log.isDebugEnabled()) {
57 60 log.debug("Executing getOAuth2Clients: [{}][{}][{}]", request.getScheme(), request.getServerName(), request.getServerPort());
... ... @@ -61,7 +64,13 @@ public class OAuth2Controller extends BaseController {
61 64 log.debug("Header: {} {}", header, request.getHeader(header));
62 65 }
63 66 }
64   - return oAuth2Service.getOAuth2Clients(MiscUtils.getScheme(request), MiscUtils.getDomainNameAndPort(request), pkgName);
  67 + PlatformType platformType = null;
  68 + if (StringUtils.isNotEmpty(platform)) {
  69 + try {
  70 + platformType = PlatformType.valueOf(platform);
  71 + } catch (Exception e) {}
  72 + }
  73 + return oAuth2Service.getOAuth2Clients(MiscUtils.getScheme(request), MiscUtils.getDomainNameAndPort(request), pkgName, platformType);
65 74 } catch (Exception e) {
66 75 throw handleException(e);
67 76 }
... ...
... ... @@ -199,6 +199,7 @@ public class ThingsboardInstallService {
199 199 databaseEntitiesUpgradeService.upgradeDatabase("3.2.2");
200 200
201 201 dataUpdateService.updateData("3.2.2");
  202 + systemDataLoaderService.createOAuth2Templates();
202 203
203 204 log.info("Updating system data...");
204 205 systemDataLoaderService.updateSystemWidgets();
... ...
... ... @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.oauth2;
18 18 import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo;
19 19 import org.thingsboard.server.common.data.oauth2.OAuth2Info;
20 20 import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
  21 +import org.thingsboard.server.common.data.oauth2.PlatformType;
21 22 import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientRegistrationInfo;
22 23 import org.thingsboard.server.common.data.oauth2.deprecated.OAuth2ClientsParams;
23 24
... ... @@ -25,7 +26,7 @@ import java.util.List;
25 26 import java.util.UUID;
26 27
27 28 public interface OAuth2Service {
28   - List<OAuth2ClientInfo> getOAuth2Clients(String domainScheme, String domainName, String pkgName);
  29 + List<OAuth2ClientInfo> getOAuth2Clients(String domainScheme, String domainName, String pkgName, PlatformType platformType);
29 30
30 31 @Deprecated
31 32 void saveOAuth2Params(OAuth2ClientsParams oauth2Params);
... ...
... ... @@ -46,6 +46,7 @@ public class OAuth2Registration extends SearchTextBasedWithAdditionalInfo<OAuth2
46 46 private String clientAuthenticationMethod;
47 47 private String loginButtonLabel;
48 48 private String loginButtonIcon;
  49 + private List<PlatformType> platforms;
49 50
50 51 public OAuth2Registration(OAuth2Registration registration) {
51 52 super(registration);
... ... @@ -62,6 +63,7 @@ public class OAuth2Registration extends SearchTextBasedWithAdditionalInfo<OAuth2
62 63 this.clientAuthenticationMethod = registration.clientAuthenticationMethod;
63 64 this.loginButtonLabel = registration.loginButtonLabel;
64 65 this.loginButtonIcon = registration.loginButtonIcon;
  66 + this.platforms = registration.platforms;
65 67 }
66 68
67 69 @Override
... ...
... ... @@ -39,5 +39,6 @@ public class OAuth2RegistrationInfo {
39 39 private String clientAuthenticationMethod;
40 40 private String loginButtonLabel;
41 41 private String loginButtonIcon;
  42 + private List<PlatformType> platforms;
42 43 private JsonNode additionalInfo;
43 44 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.oauth2;
  17 +
  18 +public enum PlatformType {
  19 + WEB, ANDROID, IOS
  20 +}
... ...
... ... @@ -433,6 +433,7 @@ public class ModelConstants {
433 433 public static final String OAUTH2_AUTHORIZATION_URI_PROPERTY = "authorization_uri";
434 434 public static final String OAUTH2_TOKEN_URI_PROPERTY = "token_uri";
435 435 public static final String OAUTH2_SCOPE_PROPERTY = "scope";
  436 + public static final String OAUTH2_PLATFORMS_PROPERTY = "platforms";
436 437 public static final String OAUTH2_USER_INFO_URI_PROPERTY = "user_info_uri";
437 438 public static final String OAUTH2_USER_NAME_ATTRIBUTE_NAME_PROPERTY = "user_name_attribute_name";
438 439 public static final String OAUTH2_JWK_SET_URI_PROPERTY = "jwk_set_uri";
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.dao.model.sql;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import io.micrometer.core.instrument.util.StringUtils;
19 20 import lombok.Data;
20 21 import lombok.EqualsAndHashCode;
21 22 import org.hibernate.annotations.Type;
... ... @@ -27,6 +28,7 @@ import org.thingsboard.server.common.data.oauth2.OAuth2BasicMapperConfig;
27 28 import org.thingsboard.server.common.data.oauth2.OAuth2CustomMapperConfig;
28 29 import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig;
29 30 import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
  31 +import org.thingsboard.server.common.data.oauth2.PlatformType;
30 32 import org.thingsboard.server.common.data.oauth2.TenantNameStrategyType;
31 33 import org.thingsboard.server.dao.model.BaseSqlEntity;
32 34 import org.thingsboard.server.dao.model.ModelConstants;
... ... @@ -38,7 +40,9 @@ import javax.persistence.EnumType;
38 40 import javax.persistence.Enumerated;
39 41 import javax.persistence.Table;
40 42 import java.util.Arrays;
  43 +import java.util.Collections;
41 44 import java.util.UUID;
  45 +import java.util.stream.Collectors;
42 46
43 47 @Data
44 48 @EqualsAndHashCode(callSuper = true)
... ... @@ -59,6 +63,8 @@ public class OAuth2RegistrationEntity extends BaseSqlEntity<OAuth2Registration>
59 63 private String tokenUri;
60 64 @Column(name = ModelConstants.OAUTH2_SCOPE_PROPERTY)
61 65 private String scope;
  66 + @Column(name = ModelConstants.OAUTH2_PLATFORMS_PROPERTY)
  67 + private String platforms;
62 68 @Column(name = ModelConstants.OAUTH2_USER_INFO_URI_PROPERTY)
63 69 private String userInfoUri;
64 70 @Column(name = ModelConstants.OAUTH2_USER_NAME_ATTRIBUTE_NAME_PROPERTY)
... ... @@ -125,6 +131,7 @@ public class OAuth2RegistrationEntity extends BaseSqlEntity<OAuth2Registration>
125 131 this.authorizationUri = registration.getAuthorizationUri();
126 132 this.tokenUri = registration.getAccessTokenUri();
127 133 this.scope = registration.getScope().stream().reduce((result, element) -> result + "," + element).orElse("");
  134 + this.platforms = registration.getPlatforms() != null ? registration.getPlatforms().stream().map(Enum::name).reduce((result, element) -> result + "," + element).orElse("") : "";
128 135 this.userInfoUri = registration.getUserInfoUri();
129 136 this.userNameAttributeName = registration.getUserNameAttributeName();
130 137 this.jwkSetUri = registration.getJwkSetUri();
... ... @@ -201,6 +208,8 @@ public class OAuth2RegistrationEntity extends BaseSqlEntity<OAuth2Registration>
201 208 registration.setAuthorizationUri(authorizationUri);
202 209 registration.setAccessTokenUri(tokenUri);
203 210 registration.setScope(Arrays.asList(scope.split(",")));
  211 + registration.setPlatforms(StringUtils.isNotEmpty(platforms) ? Arrays.stream(platforms.split(","))
  212 + .map(str -> PlatformType.valueOf(str)).collect(Collectors.toList()) : Collections.emptyList());
204 213 registration.setUserInfoUri(userInfoUri);
205 214 registration.setUserNameAttributeName(userNameAttributeName);
206 215 registration.setJwkSetUri(jwkSetUri);
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.dao.oauth2;
17 17
18 18 import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
  19 +import org.thingsboard.server.common.data.oauth2.PlatformType;
19 20 import org.thingsboard.server.common.data.oauth2.SchemeType;
20 21 import org.thingsboard.server.dao.Dao;
21 22
... ... @@ -24,7 +25,7 @@ import java.util.UUID;
24 25
25 26 public interface OAuth2RegistrationDao extends Dao<OAuth2Registration> {
26 27
27   - List<OAuth2Registration> findEnabledByDomainSchemesDomainNameAndPkgName(List<SchemeType> domainSchemes, String domainName, String pkgName);
  28 + List<OAuth2Registration> findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(List<SchemeType> domainSchemes, String domainName, String pkgName, PlatformType platformType);
28 29
29 30 List<OAuth2Registration> findByOAuth2ParamsId(UUID oauth2ParamsId);
30 31
... ...
... ... @@ -65,8 +65,8 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
65 65 private OAuth2MobileDao oauth2MobileDao;
66 66
67 67 @Override
68   - public List<OAuth2ClientInfo> getOAuth2Clients(String domainSchemeStr, String domainName, String pkgName) {
69   - log.trace("Executing getOAuth2Clients [{}://{}]", domainSchemeStr, domainName);
  68 + public List<OAuth2ClientInfo> getOAuth2Clients(String domainSchemeStr, String domainName, String pkgName, PlatformType platformType) {
  69 + log.trace("Executing getOAuth2Clients [{}://{}] pkgName=[{}] platformType=[{}]", domainSchemeStr, domainName, pkgName, platformType);
70 70 if (domainSchemeStr == null) {
71 71 throw new IncorrectParameterException(INCORRECT_DOMAIN_SCHEME);
72 72 }
... ... @@ -77,7 +77,9 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
77 77 throw new IncorrectParameterException(INCORRECT_DOMAIN_SCHEME);
78 78 }
79 79 validateString(domainName, INCORRECT_DOMAIN_NAME + domainName);
80   - return oauth2RegistrationDao.findEnabledByDomainSchemesDomainNameAndPkgName(Arrays.asList(domainScheme, SchemeType.MIXED), domainName, pkgName).stream()
  80 + return oauth2RegistrationDao.findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(
  81 + Arrays.asList(domainScheme, SchemeType.MIXED), domainName, pkgName, platformType)
  82 + .stream()
81 83 .map(OAuth2Utils::toClientInfo)
82 84 .collect(Collectors.toList());
83 85 }
... ...
... ... @@ -127,6 +127,7 @@ public class OAuth2Utils {
127 127 .authorizationUri(registration.getAuthorizationUri())
128 128 .accessTokenUri(registration.getAccessTokenUri())
129 129 .scope(registration.getScope())
  130 + .platforms(registration.getPlatforms())
130 131 .userInfoUri(registration.getUserInfoUri())
131 132 .userNameAttributeName(registration.getUserNameAttributeName())
132 133 .jwkSetUri(registration.getJwkSetUri())
... ... @@ -167,6 +168,7 @@ public class OAuth2Utils {
167 168 registration.setAuthorizationUri(registrationInfo.getAuthorizationUri());
168 169 registration.setAccessTokenUri(registrationInfo.getAccessTokenUri());
169 170 registration.setScope(registrationInfo.getScope());
  171 + registration.setPlatforms(registrationInfo.getPlatforms());
170 172 registration.setUserInfoUri(registrationInfo.getUserInfoUri());
171 173 registration.setUserNameAttributeName(registrationInfo.getUserNameAttributeName());
172 174 registration.setJwkSetUri(registrationInfo.getJwkSetUri());
... ... @@ -224,6 +226,7 @@ public class OAuth2Utils {
224 226 .loginButtonLabel(clientRegistrationDto.getLoginButtonLabel())
225 227 .loginButtonIcon(clientRegistrationDto.getLoginButtonIcon())
226 228 .additionalInfo(clientRegistrationDto.getAdditionalInfo())
  229 + .platforms(Collections.emptyList())
227 230 .build();
228 231 }
229 232
... ...
... ... @@ -19,6 +19,7 @@ import lombok.RequiredArgsConstructor;
19 19 import org.springframework.data.repository.CrudRepository;
20 20 import org.springframework.stereotype.Component;
21 21 import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
  22 +import org.thingsboard.server.common.data.oauth2.PlatformType;
22 23 import org.thingsboard.server.common.data.oauth2.SchemeType;
23 24 import org.thingsboard.server.dao.DaoUtil;
24 25 import org.thingsboard.server.dao.model.sql.OAuth2RegistrationEntity;
... ... @@ -45,8 +46,9 @@ public class JpaOAuth2RegistrationDao extends JpaAbstractDao<OAuth2RegistrationE
45 46 }
46 47
47 48 @Override
48   - public List<OAuth2Registration> findEnabledByDomainSchemesDomainNameAndPkgName(List<SchemeType> domainSchemes, String domainName, String pkgName) {
49   - return DaoUtil.convertDataList(repository.findAllEnabledByDomainSchemesNameAndPkgName(domainSchemes, domainName, pkgName));
  49 + public List<OAuth2Registration> findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(List<SchemeType> domainSchemes, String domainName, String pkgName, PlatformType platformType) {
  50 + return DaoUtil.convertDataList(repository.findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(domainSchemes, domainName, pkgName,
  51 + platformType != null ? "%" + platformType.name() + "%" : null));
50 52 }
51 53
52 54 @Override
... ...
... ... @@ -30,14 +30,15 @@ public interface OAuth2RegistrationRepository extends CrudRepository<OAuth2Regis
30 30 "FROM OAuth2RegistrationEntity reg " +
31 31 "LEFT JOIN OAuth2ParamsEntity params on reg.oauth2ParamsId = params.id " +
32 32 "LEFT JOIN OAuth2DomainEntity domain on reg.oauth2ParamsId = domain.oauth2ParamsId " +
33   - "LEFT JOIN OAuth2MobileEntity mobile on reg.oauth2ParamsId = mobile.oauth2ParamsId " +
34 33 "WHERE params.enabled = true " +
35 34 "AND domain.domainName = :domainName " +
36 35 "AND domain.domainScheme IN (:domainSchemes) " +
37   - "AND (:pkgName IS NULL OR mobile.pkgName = :pkgName)")
38   - List<OAuth2RegistrationEntity> findAllEnabledByDomainSchemesNameAndPkgName(@Param("domainSchemes") List<SchemeType> domainSchemes,
39   - @Param("domainName") String domainName,
40   - @Param("pkgName") String pkgName);
  36 + "AND (:pkgName IS NULL OR EXISTS (SELECT mobile FROM OAuth2MobileEntity mobile WHERE mobile.oauth2ParamsId = reg.oauth2ParamsId AND mobile.pkgName = :pkgName)) " +
  37 + "AND (:platformFilter IS NULL OR reg.platforms IS NULL OR reg.platforms = '' OR reg.platforms LIKE :platformFilter)")
  38 + List<OAuth2RegistrationEntity> findEnabledByDomainSchemesDomainNameAndPkgNameAndPlatformType(@Param("domainSchemes") List<SchemeType> domainSchemes,
  39 + @Param("domainName") String domainName,
  40 + @Param("pkgName") String pkgName,
  41 + @Param("platformFilter") String platformFilter);
41 42
42 43 List<OAuth2RegistrationEntity> findByOauth2ParamsId(UUID oauth2ParamsId);
43 44
... ...
... ... @@ -391,6 +391,7 @@ CREATE TABLE IF NOT EXISTS oauth2_registration (
391 391 authorization_uri varchar(255),
392 392 token_uri varchar(255),
393 393 scope varchar(255),
  394 + platforms varchar(255),
394 395 user_info_uri varchar(255),
395 396 user_name_attribute_name varchar(255),
396 397 jwk_set_uri varchar(255),
... ...
... ... @@ -428,6 +428,7 @@ CREATE TABLE IF NOT EXISTS oauth2_registration (
428 428 authorization_uri varchar(255),
429 429 token_uri varchar(255),
430 430 scope varchar(255),
  431 + platforms varchar(255),
431 432 user_info_uri varchar(255),
432 433 user_name_attribute_name varchar(255),
433 434 jwk_set_uri varchar(255),
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.dao.service;
17 17
  18 +import com.fasterxml.jackson.databind.node.ObjectNode;
18 19 import com.google.common.collect.Lists;
19 20 import org.junit.After;
20 21 import org.junit.Assert;
... ... @@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.oauth2.OAuth2MobileInfo;
31 32 import org.thingsboard.server.common.data.oauth2.OAuth2ParamsInfo;
32 33 import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
33 34 import org.thingsboard.server.common.data.oauth2.OAuth2RegistrationInfo;
  35 +import org.thingsboard.server.common.data.oauth2.PlatformType;
34 36 import org.thingsboard.server.common.data.oauth2.SchemeType;
35 37 import org.thingsboard.server.dao.exception.DataValidationException;
36 38 import org.thingsboard.server.dao.oauth2.OAuth2Service;
... ... @@ -231,10 +233,10 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
231 233 registrationInfo.getLoginButtonLabel(), registrationInfo.getLoginButtonIcon(), null))
232 234 .collect(Collectors.toList());
233 235
234   - List<OAuth2ClientInfo> nonExistentDomainClients = oAuth2Service.getOAuth2Clients("http", "non-existent-domain", null);
  236 + List<OAuth2ClientInfo> nonExistentDomainClients = oAuth2Service.getOAuth2Clients("http", "non-existent-domain", null, null);
235 237 Assert.assertTrue(nonExistentDomainClients.isEmpty());
236 238
237   - List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", null);
  239 + List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", null, null);
238 240 Assert.assertEquals(firstGroupClientInfos.size(), firstDomainHttpClients.size());
239 241 firstGroupClientInfos.forEach(firstGroupClientInfo -> {
240 242 Assert.assertTrue(
... ... @@ -244,10 +246,10 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
244 246 );
245 247 });
246 248
247   - List<OAuth2ClientInfo> firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain", null);
  249 + List<OAuth2ClientInfo> firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain", null, null);
248 250 Assert.assertTrue(firstDomainHttpsClients.isEmpty());
249 251
250   - List<OAuth2ClientInfo> fourthDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "fourth-domain", null);
  252 + List<OAuth2ClientInfo> fourthDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "fourth-domain", null, null);
251 253 Assert.assertEquals(secondGroupClientInfos.size(), fourthDomainHttpClients.size());
252 254 secondGroupClientInfos.forEach(secondGroupClientInfo -> {
253 255 Assert.assertTrue(
... ... @@ -256,7 +258,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
256 258 && clientInfo.getName().equals(secondGroupClientInfo.getName()))
257 259 );
258 260 });
259   - List<OAuth2ClientInfo> fourthDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "fourth-domain", null);
  261 + List<OAuth2ClientInfo> fourthDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "fourth-domain", null, null);
260 262 Assert.assertEquals(secondGroupClientInfos.size(), fourthDomainHttpsClients.size());
261 263 secondGroupClientInfos.forEach(secondGroupClientInfo -> {
262 264 Assert.assertTrue(
... ... @@ -266,7 +268,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
266 268 );
267 269 });
268 270
269   - List<OAuth2ClientInfo> secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null);
  271 + List<OAuth2ClientInfo> secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null, null);
270 272 Assert.assertEquals(firstGroupClientInfos.size() + secondGroupClientInfos.size(), secondDomainHttpClients.size());
271 273 firstGroupClientInfos.forEach(firstGroupClientInfo -> {
272 274 Assert.assertTrue(
... ... @@ -283,7 +285,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
283 285 );
284 286 });
285 287
286   - List<OAuth2ClientInfo> secondDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "second-domain", null);
  288 + List<OAuth2ClientInfo> secondDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "second-domain", null, null);
287 289 Assert.assertEquals(firstGroupClientInfos.size() + thirdGroupClientInfos.size(), secondDomainHttpsClients.size());
288 290 firstGroupClientInfos.forEach(firstGroupClientInfo -> {
289 291 Assert.assertTrue(
... ... @@ -331,7 +333,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
331 333 registrationInfo.getLoginButtonLabel(), registrationInfo.getLoginButtonIcon(), null))
332 334 .collect(Collectors.toList());
333 335
334   - List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", null);
  336 + List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", null, null);
335 337 Assert.assertEquals(firstGroupClientInfos.size(), firstDomainHttpClients.size());
336 338 firstGroupClientInfos.forEach(firstGroupClientInfo -> {
337 339 Assert.assertTrue(
... ... @@ -341,7 +343,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
341 343 );
342 344 });
343 345
344   - List<OAuth2ClientInfo> firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain", null);
  346 + List<OAuth2ClientInfo> firstDomainHttpsClients = oAuth2Service.getOAuth2Clients("https", "first-domain", null, null);
345 347 Assert.assertEquals(firstGroupClientInfos.size(), firstDomainHttpsClients.size());
346 348 firstGroupClientInfos.forEach(firstGroupClientInfo -> {
347 349 Assert.assertTrue(
... ... @@ -381,13 +383,13 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
381 383
382 384 oAuth2Service.saveOAuth2Info(oAuth2Info);
383 385
384   - List<OAuth2ClientInfo> secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null);
  386 + List<OAuth2ClientInfo> secondDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null, null);
385 387 Assert.assertEquals(5, secondDomainHttpClients.size());
386 388
387 389 oAuth2Info.setEnabled(false);
388 390 oAuth2Service.saveOAuth2Info(oAuth2Info);
389 391
390   - List<OAuth2ClientInfo> secondDomainHttpDisabledClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null);
  392 + List<OAuth2ClientInfo> secondDomainHttpDisabledClients = oAuth2Service.getOAuth2Clients("http", "second-domain", null, null);
391 393 Assert.assertEquals(0, secondDomainHttpDisabledClients.size());
392 394 }
393 395
... ... @@ -520,7 +522,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
520 522 OAuth2Info foundOAuth2Info = oAuth2Service.findOAuth2Info();
521 523 Assert.assertEquals(oAuth2Info, foundOAuth2Info);
522 524
523   - List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", "com.test.pkg1");
  525 + List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", "com.test.pkg1", null);
524 526 Assert.assertEquals(3, firstDomainHttpClients.size());
525 527 for (OAuth2ClientInfo clientInfo : firstDomainHttpClients) {
526 528 String[] segments = clientInfo.getUrl().split("/");
... ... @@ -536,6 +538,56 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
536 538 }
537 539 }
538 540
  541 + @Test
  542 + public void testFindClientsByPackageAndPlatform() {
  543 + OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList(
  544 + OAuth2ParamsInfo.builder()
  545 + .domainInfos(Lists.newArrayList(
  546 + OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(),
  547 + OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.MIXED).build(),
  548 + OAuth2DomainInfo.builder().name("third-domain").scheme(SchemeType.HTTPS).build()
  549 + ))
  550 + .mobileInfos(Lists.newArrayList(
  551 + OAuth2MobileInfo.builder().pkgName("com.test.pkg1").callbackUrlScheme("testPkg1Callback").build(),
  552 + OAuth2MobileInfo.builder().pkgName("com.test.pkg2").callbackUrlScheme("testPkg2Callback").build()
  553 + ))
  554 + .clientRegistrations(Lists.newArrayList(
  555 + validRegistrationInfo("Google", Arrays.asList(PlatformType.WEB, PlatformType.ANDROID)),
  556 + validRegistrationInfo("Facebook", Arrays.asList(PlatformType.IOS)),
  557 + validRegistrationInfo("GitHub", Collections.emptyList())
  558 + ))
  559 + .build(),
  560 + OAuth2ParamsInfo.builder()
  561 + .domainInfos(Lists.newArrayList(
  562 + OAuth2DomainInfo.builder().name("second-domain").scheme(SchemeType.HTTP).build(),
  563 + OAuth2DomainInfo.builder().name("fourth-domain").scheme(SchemeType.MIXED).build()
  564 + ))
  565 + .mobileInfos(Collections.emptyList())
  566 + .clientRegistrations(Lists.newArrayList(
  567 + validRegistrationInfo(),
  568 + validRegistrationInfo()
  569 + ))
  570 + .build()
  571 + ));
  572 + oAuth2Service.saveOAuth2Info(oAuth2Info);
  573 +
  574 + OAuth2Info foundOAuth2Info = oAuth2Service.findOAuth2Info();
  575 + Assert.assertEquals(oAuth2Info, foundOAuth2Info);
  576 +
  577 + List<OAuth2ClientInfo> firstDomainHttpClients = oAuth2Service.getOAuth2Clients("http", "first-domain", null, null);
  578 + Assert.assertEquals(3, firstDomainHttpClients.size());
  579 + List<OAuth2ClientInfo> pkg1Clients = oAuth2Service.getOAuth2Clients("http", "first-domain", "com.test.pkg1", null);
  580 + Assert.assertEquals(3, pkg1Clients.size());
  581 + List<OAuth2ClientInfo> pkg1AndroidClients = oAuth2Service.getOAuth2Clients("http", "first-domain", "com.test.pkg1", PlatformType.ANDROID);
  582 + Assert.assertEquals(2, pkg1AndroidClients.size());
  583 + Assert.assertTrue(pkg1AndroidClients.stream().anyMatch(client -> client.getName().equals("Google")));
  584 + Assert.assertTrue(pkg1AndroidClients.stream().anyMatch(client -> client.getName().equals("GitHub")));
  585 + List<OAuth2ClientInfo> pkg1IOSClients = oAuth2Service.getOAuth2Clients("http", "first-domain", "com.test.pkg1", PlatformType.IOS);
  586 + Assert.assertEquals(2, pkg1IOSClients.size());
  587 + Assert.assertTrue(pkg1IOSClients.stream().anyMatch(client -> client.getName().equals("Facebook")));
  588 + Assert.assertTrue(pkg1IOSClients.stream().anyMatch(client -> client.getName().equals("GitHub")));
  589 + }
  590 +
539 591 private OAuth2Info createDefaultOAuth2Info() {
540 592 return new OAuth2Info(true, Lists.newArrayList(
541 593 OAuth2ParamsInfo.builder()
... ... @@ -567,17 +619,22 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
567 619 }
568 620
569 621 private OAuth2RegistrationInfo validRegistrationInfo() {
  622 + return validRegistrationInfo(null, Collections.emptyList());
  623 + }
  624 +
  625 + private OAuth2RegistrationInfo validRegistrationInfo(String label, List<PlatformType> platforms) {
570 626 return OAuth2RegistrationInfo.builder()
571 627 .clientId(UUID.randomUUID().toString())
572 628 .clientSecret(UUID.randomUUID().toString())
573 629 .authorizationUri(UUID.randomUUID().toString())
574 630 .accessTokenUri(UUID.randomUUID().toString())
575 631 .scope(Arrays.asList(UUID.randomUUID().toString(), UUID.randomUUID().toString()))
  632 + .platforms(platforms == null ? Collections.emptyList() : platforms)
576 633 .userInfoUri(UUID.randomUUID().toString())
577 634 .userNameAttributeName(UUID.randomUUID().toString())
578 635 .jwkSetUri(UUID.randomUUID().toString())
579 636 .clientAuthenticationMethod(UUID.randomUUID().toString())
580   - .loginButtonLabel(UUID.randomUUID().toString())
  637 + .loginButtonLabel(label != null ? label : UUID.randomUUID().toString())
581 638 .loginButtonIcon(UUID.randomUUID().toString())
582 639 .additionalInfo(mapper.createObjectNode().put(UUID.randomUUID().toString(), UUID.randomUUID().toString()))
583 640 .mapperConfig(
... ...
... ... @@ -44,7 +44,7 @@ import { AdminService } from '@core/http/admin.service';
44 44 import { ActionNotificationShow } from '@core/notification/notification.actions';
45 45 import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
46 46 import { AlertDialogComponent } from '@shared/components/dialog/alert-dialog.component';
47   -import { OAuth2ClientInfo } from '@shared/models/oauth2.models';
  47 +import { OAuth2ClientInfo, PlatformType } from '@shared/models/oauth2.models';
48 48 import { isDefinedAndNotNull, isMobileApp } from '@core/utils';
49 49
50 50 @Injectable({
... ... @@ -204,11 +204,8 @@ export class AuthService {
204 204 }
205 205 }
206 206
207   - public loadOAuth2Clients(pkgName?: string): Observable<Array<OAuth2ClientInfo>> {
208   - let url = '/api/noauth/oauth2Clients';
209   - if (isDefinedAndNotNull(pkgName)) {
210   - url += `?pkgName=${pkgName}`;
211   - }
  207 + public loadOAuth2Clients(): Observable<Array<OAuth2ClientInfo>> {
  208 + const url = '/api/noauth/oauth2Clients?platform=' + PlatformType.WEB;
212 209 return this.http.post<Array<OAuth2ClientInfo>>(url,
213 210 null, defaultHttpOptions()).pipe(
214 211 catchError(err => of([])),
... ...
... ... @@ -201,18 +201,27 @@
201 201
202 202 <ng-template matExpansionPanelContent>
203 203 <section [formGroupName]="j">
204   - <section formGroupName="additionalInfo" fxLayout="row">
205   - <mat-form-field fxFlex class="mat-block">
206   - <mat-label translate>admin.oauth2.login-provider</mat-label>
207   - <mat-select formControlName="providerName">
208   - <mat-option *ngFor="let provider of templateProvider" [value]="provider">
209   - {{ provider }}
  204 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
  205 + <section fxFlex formGroupName="additionalInfo" fxLayout="row">
  206 + <mat-form-field fxFlex class="mat-block">
  207 + <mat-label translate>admin.oauth2.login-provider</mat-label>
  208 + <mat-select formControlName="providerName">
  209 + <mat-option *ngFor="let provider of templateProvider" [value]="provider">
  210 + {{ provider }}
  211 + </mat-option>
  212 + </mat-select>
  213 + </mat-form-field>
  214 + <div [tb-help]="getHelpLink(registration)" *ngIf="!isCustomProvider(registration)"></div>
  215 + </section>
  216 + <mat-form-field floatLabel="always" fxFlex class="mat-block">
  217 + <mat-label translate>admin.oauth2.allowed-platforms</mat-label>
  218 + <mat-select formControlName="platforms" multiple placeholder="{{ 'admin.oauth2.all-platforms' | translate }}">
  219 + <mat-option *ngFor="let platform of platformTypes" [value]="platform">
  220 + {{ platformTypeTranslations.get(platform) | translate }}
210 221 </mat-option>
211 222 </mat-select>
212 223 </mat-form-field>
213   - <div [tb-help]="getHelpLink(registration)" *ngIf="!isCustomProvider(registration)"></div>
214   - </section>
215   -
  224 + </div>
216 225 <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
217 226 <mat-form-field fxFlex class="mat-block">
218 227 <mat-label translate>admin.oauth2.client-id</mat-label>
... ...
... ... @@ -28,7 +28,8 @@ import {
28 28 OAuth2DomainInfo,
29 29 OAuth2Info, OAuth2MobileInfo,
30 30 OAuth2ParamsInfo,
31   - OAuth2RegistrationInfo,
  31 + OAuth2RegistrationInfo, PlatformType,
  32 + platformTypeTranslations,
32 33 TenantNameStrategy
33 34 } from '@shared/models/oauth2.models';
34 35 import { Store } from '@ngrx/store';
... ... @@ -99,6 +100,8 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
99 100 tenantNameStrategies = Object.keys(TenantNameStrategy);
100 101 protocols = Object.keys(DomainSchema);
101 102 domainSchemaTranslations = domainSchemaTranslations;
  103 + platformTypes = Object.keys(PlatformType);
  104 + platformTypeTranslations = platformTypeTranslations;
102 105
103 106 templateProvider = ['Custom'];
104 107
... ... @@ -293,6 +296,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
293 296 additionalInfo: this.fb.group({
294 297 providerName: [additionalInfo?.providerName ? additionalInfo?.providerName : defaultProviderName, Validators.required]
295 298 }),
  299 + platforms: [registration?.platforms ? registration.platforms : []],
296 300 loginButtonLabel: [registration?.loginButtonLabel ? registration.loginButtonLabel : null, Validators.required],
297 301 loginButtonIcon: [registration?.loginButtonIcon ? registration.loginButtonIcon : null],
298 302 clientId: [registration?.clientId ? registration.clientId : '', Validators.required],
... ...
... ... @@ -63,6 +63,20 @@ export enum TenantNameStrategy{
63 63 CUSTOM = 'CUSTOM'
64 64 }
65 65
  66 +export enum PlatformType {
  67 + WEB = 'WEB',
  68 + ANDROID = 'ANDROID',
  69 + IOS = 'IOS'
  70 +}
  71 +
  72 +export const platformTypeTranslations = new Map<PlatformType, string>(
  73 + [
  74 + [PlatformType.WEB, 'admin.oauth2.platform-web'],
  75 + [PlatformType.ANDROID, 'admin.oauth2.platform-android'],
  76 + [PlatformType.IOS, 'admin.oauth2.platform-ios']
  77 + ]
  78 +);
  79 +
66 80 export interface OAuth2ClientRegistrationTemplate extends OAuth2RegistrationInfo{
67 81 comment: string;
68 82 createdTime: number;
... ... @@ -80,6 +94,7 @@ export interface OAuth2RegistrationInfo {
80 94 accessTokenUri: string;
81 95 authorizationUri: string;
82 96 scope: string[];
  97 + platforms: PlatformType[];
83 98 jwkSetUri?: string;
84 99 userInfoUri: string;
85 100 clientAuthenticationMethod: ClientAuthenticationMethod;
... ...
... ... @@ -228,7 +228,12 @@
228 228 "mobile-callback-url-scheme": "Callback URL scheme",
229 229 "add-mobile-app": "Add application",
230 230 "delete-mobile-app": "Delete application info",
231   - "providers": "Providers"
  231 + "providers": "Providers",
  232 + "platform-web": "Web",
  233 + "platform-android": "Android",
  234 + "platform-ios": "iOS",
  235 + "all-platforms": "All platforms",
  236 + "allowed-platforms": "Allowed platforms"
232 237 }
233 238 },
234 239 "alarm": {
... ...