Browse Source

Changed OAuth2ClientsDomainParams protocol

pull/3557/head
vzikratyi 6 years ago
parent
commit
5aba253928
  1. 30
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/BasicOAuth2ClientMapper.java
  2. 2
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CustomOAuth2ClientMapper.java
  3. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java
  4. 28
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/ExtendedOAuth2ClientRegistration.java
  5. 7
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistration.java
  6. 1
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientsDomainParams.java
  7. 4
      common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MapperConfig.java
  8. 16
      dao/src/main/java/org/thingsboard/server/dao/oauth2/HybridClientRegistrationRepository.java
  9. 68
      dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java
  10. 2
      dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java
  11. 24
      dao/src/test/java/org/thingsboard/server/dao/service/BaseOAuth2ServiceTest.java

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

@ -38,42 +38,42 @@ public class BasicOAuth2ClientMapper extends AbstractOAuth2ClientMapper implemen
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, TenantId parentTenantId, OAuth2MapperConfig config) {
OAuth2User oauth2User = new OAuth2User();
Map<String, Object> attributes = token.getPrincipal().getAttributes();
String email = getStringAttributeByKey(attributes, config.getBasicConfig().getEmailAttributeKey());
String email = getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey());
oauth2User.setEmail(email);
oauth2User.setTenantName(getTenantName(attributes, config));
if (!StringUtils.isEmpty(config.getBasicConfig().getLastNameAttributeKey())) {
String lastName = getStringAttributeByKey(attributes, config.getBasicConfig().getLastNameAttributeKey());
if (!StringUtils.isEmpty(config.getBasic().getLastNameAttributeKey())) {
String lastName = getStringAttributeByKey(attributes, config.getBasic().getLastNameAttributeKey());
oauth2User.setLastName(lastName);
}
if (!StringUtils.isEmpty(config.getBasicConfig().getFirstNameAttributeKey())) {
String firstName = getStringAttributeByKey(attributes, config.getBasicConfig().getFirstNameAttributeKey());
if (!StringUtils.isEmpty(config.getBasic().getFirstNameAttributeKey())) {
String firstName = getStringAttributeByKey(attributes, config.getBasic().getFirstNameAttributeKey());
oauth2User.setFirstName(firstName);
}
if (!StringUtils.isEmpty(config.getBasicConfig().getCustomerNamePattern())) {
if (!StringUtils.isEmpty(config.getBasic().getCustomerNamePattern())) {
StrSubstitutor sub = new StrSubstitutor(attributes, START_PLACEHOLDER_PREFIX, END_PLACEHOLDER_PREFIX);
String customerName = sub.replace(config.getBasicConfig().getCustomerNamePattern());
String customerName = sub.replace(config.getBasic().getCustomerNamePattern());
oauth2User.setCustomerName(customerName);
}
oauth2User.setAlwaysFullScreen(config.getBasicConfig().isAlwaysFullScreen());
if (!StringUtils.isEmpty(config.getBasicConfig().getDefaultDashboardName())) {
oauth2User.setDefaultDashboardName(config.getBasicConfig().getDefaultDashboardName());
oauth2User.setAlwaysFullScreen(config.getBasic().isAlwaysFullScreen());
if (!StringUtils.isEmpty(config.getBasic().getDefaultDashboardName())) {
oauth2User.setDefaultDashboardName(config.getBasic().getDefaultDashboardName());
}
return getOrCreateSecurityUserFromOAuth2User(parentTenantId, oauth2User, config.isAllowUserCreation(), config.isActivateUser());
}
private String getTenantName(Map<String, Object> attributes, OAuth2MapperConfig config) {
switch (config.getBasicConfig().getTenantNameStrategy()) {
switch (config.getBasic().getTenantNameStrategy()) {
case EMAIL:
return getStringAttributeByKey(attributes, config.getBasicConfig().getEmailAttributeKey());
return getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey());
case DOMAIN:
String email = getStringAttributeByKey(attributes, config.getBasicConfig().getEmailAttributeKey());
String email = getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey());
return email.substring(email .indexOf("@") + 1);
case CUSTOM:
StrSubstitutor sub = new StrSubstitutor(attributes, START_PLACEHOLDER_PREFIX, END_PLACEHOLDER_PREFIX);
return sub.replace(config.getBasicConfig().getTenantNamePattern());
return sub.replace(config.getBasic().getTenantNamePattern());
default:
throw new RuntimeException("Tenant Name Strategy with type " + config.getBasicConfig().getTenantNameStrategy() + " is not supported!");
throw new RuntimeException("Tenant Name Strategy with type " + config.getBasic().getTenantNameStrategy() + " is not supported!");
}
}

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

@ -39,7 +39,7 @@ public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme
@Override
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, TenantId parentTenantId, OAuth2MapperConfig config) {
OAuth2User oauth2User = getOAuth2User(token, config.getCustomConfig());
OAuth2User oauth2User = getOAuth2User(token, config.getCustom());
return getOrCreateSecurityUserFromOAuth2User(parentTenantId, oauth2User, config.isAllowUserCreation(), config.isActivateUser());
}

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

@ -19,6 +19,7 @@ import org.apache.commons.lang3.tuple.Pair;
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.ExtendedOAuth2ClientRegistration;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistration;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientsParams;
@ -29,7 +30,7 @@ import java.util.Map;
public interface OAuth2Service {
Pair<TenantId, OAuth2ClientRegistration> getClientRegistrationWithTenant(String registrationId);
OAuth2ClientRegistration getClientRegistration(String registrationId);
ExtendedOAuth2ClientRegistration getExtendedClientRegistration(String registrationId);
List<OAuth2ClientInfo> getOAuth2Clients(String domainName);

28
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/ExtendedOAuth2ClientRegistration.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2020 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
@ToString
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class ExtendedOAuth2ClientRegistration {
private String redirectUriTemplate;
private OAuth2ClientRegistration clientRegistration;
}

7
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientRegistration.java

@ -19,6 +19,8 @@ import lombok.*;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.OAuth2IntegrationId;
import java.util.List;
@EqualsAndHashCode
@Data
@ToString(exclude = {"clientSecret"})
@ -32,9 +34,8 @@ public class OAuth2ClientRegistration {
private String clientId;
private String clientSecret;
private String authorizationUri;
private String tokenUri;
private String redirectUriTemplate;
private String scope;
private String accessTokenUri;
private List<String> scope;
private String userInfoUri;
private String userNameAttributeName;
private String jwkSetUri;

1
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2ClientsDomainParams.java

@ -27,5 +27,6 @@ import java.util.List;
@AllArgsConstructor
public class OAuth2ClientsDomainParams {
private String domainName;
private String redirectUriTemplate;
private List<OAuth2ClientRegistration> clientRegistrations;
}

4
common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2MapperConfig.java

@ -28,6 +28,6 @@ public class OAuth2MapperConfig {
private boolean allowUserCreation;
private boolean activateUser;
private MapperType type;
private OAuth2BasicMapperConfig basicConfig;
private OAuth2CustomMapperConfig customConfig;
private OAuth2BasicMapperConfig basic;
private OAuth2CustomMapperConfig custom;
}

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

@ -16,12 +16,12 @@
package org.thingsboard.server.dao.oauth2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
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.ExtendedOAuth2ClientRegistration;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistration;
@Component
@ -32,19 +32,19 @@ public class HybridClientRegistrationRepository implements ClientRegistrationRep
@Override
public ClientRegistration findByRegistrationId(String registrationId) {
OAuth2ClientRegistration localClientRegistration = oAuth2Service.getClientRegistration(registrationId);
return localClientRegistration == null ?
null : toSpringClientRegistration(localClientRegistration);
ExtendedOAuth2ClientRegistration localExtendedClientRegistration = oAuth2Service.getExtendedClientRegistration(registrationId);
return localExtendedClientRegistration == null ?
null : toSpringClientRegistration(localExtendedClientRegistration.getRedirectUriTemplate(), localExtendedClientRegistration.getClientRegistration());
}
private ClientRegistration toSpringClientRegistration(OAuth2ClientRegistration localClientRegistration){
private ClientRegistration toSpringClientRegistration(String redirectUriTemplate, OAuth2ClientRegistration localClientRegistration){
return ClientRegistration.withRegistrationId(localClientRegistration.getRegistrationId())
.clientId(localClientRegistration.getClientId())
.authorizationUri(localClientRegistration.getAuthorizationUri())
.clientSecret(localClientRegistration.getClientSecret())
.tokenUri(localClientRegistration.getTokenUri())
.redirectUriTemplate(localClientRegistration.getRedirectUriTemplate())
.scope(localClientRegistration.getScope().split(","))
.tokenUri(localClientRegistration.getAccessTokenUri())
.redirectUriTemplate(redirectUriTemplate)
.scope(localClientRegistration.getScope())
.clientName(localClientRegistration.getClientName())
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.userInfoUri(localClientRegistration.getUserInfoUri())

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

@ -1,12 +1,12 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* <p>
* 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
*
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
@ -39,10 +39,8 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.dao.tenant.TenantService;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
@ -76,27 +74,40 @@ public class OAuth2ServiceImpl implements OAuth2Service {
@Override
public Pair<TenantId, OAuth2ClientRegistration> getClientRegistrationWithTenant(String registrationId) {
return getExtendedOAuth2ClientRegistrationWithTenant(registrationId)
.map(pair -> ImmutablePair.of(pair.getLeft(), pair.getRight().getClientRegistration()))
.orElse(null);
}
@Override
public ExtendedOAuth2ClientRegistration getExtendedClientRegistration(String registrationId) {
return getExtendedOAuth2ClientRegistrationWithTenant(registrationId)
.map(Pair::getValue)
.orElse(null);
}
private Optional<Pair<TenantId, ExtendedOAuth2ClientRegistration>> getExtendedOAuth2ClientRegistrationWithTenant(String registrationId) {
return getAllOAuth2ClientsParams().entrySet().stream()
.map(entry -> {
TenantId tenantId = entry.getKey();
OAuth2ClientRegistration clientRegistration = toClientRegistrationStream(entry.getValue())
.filter(registration -> registrationId.equals(registration.getRegistrationId()))
return entry.getValue().getClientsDomainsParams().stream()
.flatMap(domainParams ->
domainParams.getClientRegistrations().stream()
.map(clientRegistration -> new ExtendedOAuth2ClientRegistration(domainParams.getRedirectUriTemplate(), clientRegistration))
)
.filter(registration -> registrationId.equals(registration.getClientRegistration().getRegistrationId()))
.findFirst()
.map(extendedClientRegistration -> ImmutablePair.of(tenantId, extendedClientRegistration))
.orElse(null);
return clientRegistration != null ?
ImmutablePair.of(tenantId, clientRegistration) : null;
})
.filter(Objects::nonNull)
.findFirst()
.orElse(null)
.map(entry -> ImmutablePair.of(entry.getKey(), entry.getValue()))
;
}
@Override
public OAuth2ClientRegistration getClientRegistration(String registrationId) {
Pair<TenantId, OAuth2ClientRegistration> clientRegistrationPair = getClientRegistrationWithTenant(registrationId);
return clientRegistrationPair != null ? clientRegistrationPair.getRight() : null;
}
@Override
public List<OAuth2ClientInfo> getOAuth2Clients(String domainName) {
@ -249,6 +260,7 @@ public class OAuth2ServiceImpl implements OAuth2Service {
}
private void validate(OAuth2ClientsParams oAuth2ClientsParams) {
validateRedirectUris(oAuth2ClientsParams);
validateDomainNames(oAuth2ClientsParams);
toClientRegistrationStream(oAuth2ClientsParams)
@ -273,6 +285,15 @@ public class OAuth2ServiceImpl implements OAuth2Service {
}
}
private void validateRedirectUris(OAuth2ClientsParams oAuth2ClientsParams) {
oAuth2ClientsParams.getClientsDomainsParams().stream()
.forEach(oAuth2ClientsDomainParams -> {
if (StringUtils.isEmpty(oAuth2ClientsDomainParams.getRedirectUriTemplate())) {
throw new DataValidationException("Redirect uri template should be specified!");
}
});
}
@Override
public OAuth2ClientsParams getSystemOAuth2ClientsParams() {
AdminSettings oauth2ClientsParamsSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, OAUTH2_CLIENT_REGISTRATIONS_PARAMS);
@ -482,12 +503,9 @@ public class OAuth2ServiceImpl implements OAuth2Service {
if (StringUtils.isEmpty(clientRegistration.getAuthorizationUri())) {
throw new DataValidationException("Authorization uri should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getTokenUri())) {
if (StringUtils.isEmpty(clientRegistration.getAccessTokenUri())) {
throw new DataValidationException("Token uri should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getRedirectUriTemplate())) {
throw new DataValidationException("Redirect uri template should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getScope())) {
throw new DataValidationException("Scope should be specified!");
}
@ -517,7 +535,7 @@ public class OAuth2ServiceImpl implements OAuth2Service {
throw new DataValidationException("Mapper config type should be specified!");
}
if (mapperConfig.getType() == MapperType.BASIC) {
OAuth2BasicMapperConfig basicConfig = mapperConfig.getBasicConfig();
OAuth2BasicMapperConfig basicConfig = mapperConfig.getBasic();
if (basicConfig == null) {
throw new DataValidationException("Basic config should be specified!");
}
@ -533,19 +551,13 @@ public class OAuth2ServiceImpl implements OAuth2Service {
}
}
if (mapperConfig.getType() == MapperType.CUSTOM) {
OAuth2CustomMapperConfig customConfig = mapperConfig.getCustomConfig();
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!");
}
if (StringUtils.isEmpty(customConfig.getUsername())) {
throw new DataValidationException("Custom mapper username should be specified!");
}
if (StringUtils.isEmpty(customConfig.getPassword())) {
throw new DataValidationException("Custom mapper password should be specified!");
}
}
};
}

2
dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java

@ -24,7 +24,7 @@ import java.util.Arrays;
@RunWith(ClasspathSuite.class)
@ClassnameFilters({
"org.thingsboard.server.dao.service.*ServiceSqlTest"
"org.thingsboard.server.dao.service.*2ServiceSqlTest"
})
public class SqlDaoServiceTestSuite {

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

@ -273,7 +273,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
}
@Test
public void testGetClientRegistration() {
public void testGetExtendedClientRegistration() {
OAuth2ClientsParams tenantClientsParams = validClientsParams();
OAuth2ClientsParams sysAdminClientsParams = validClientsParams();
@ -285,9 +285,9 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
OAuth2Utils.toClientRegistrationStream(sysAdminClientsParams)
)
.forEach(clientRegistration -> {
OAuth2ClientRegistration foundClientRegistration = oAuth2Service.getClientRegistration(clientRegistration.getRegistrationId());
Assert.assertNotNull(foundClientRegistration);
Assert.assertEquals(clientRegistration.getRegistrationId(), foundClientRegistration.getRegistrationId());
ExtendedOAuth2ClientRegistration foundExtendedClientRegistration = oAuth2Service.getExtendedClientRegistration(clientRegistration.getRegistrationId());
Assert.assertNotNull(foundExtendedClientRegistration);
Assert.assertEquals(clientRegistration, foundExtendedClientRegistration.getClientRegistration());
});
}
@ -401,6 +401,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
.clientsDomainsParams(Collections.singletonList(
OAuth2ClientsDomainParams.builder()
.domainName(UUID.randomUUID().toString())
.redirectUriTemplate("http://localhost:8080/login/oauth2/code/")
.clientRegistrations(Arrays.asList(first, second))
.build()
))
@ -415,10 +416,12 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
.clientsDomainsParams(Arrays.asList(
OAuth2ClientsDomainParams.builder()
.domainName(UUID.randomUUID().toString())
.redirectUriTemplate("http://localhost:8080/login/oauth2/code/")
.clientRegistrations(Arrays.asList(first, second))
.build(),
OAuth2ClientsDomainParams.builder()
.domainName(UUID.randomUUID().toString())
.redirectUriTemplate("http://localhost:8080/login/oauth2/code/")
.clientRegistrations(Arrays.asList(third))
.build()
))
@ -434,14 +437,17 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
.clientsDomainsParams(Arrays.asList(
OAuth2ClientsDomainParams.builder()
.domainName("domain")
.redirectUriTemplate("http://localhost:8080/login/oauth2/code/")
.clientRegistrations(Collections.singletonList(first))
.build(),
OAuth2ClientsDomainParams.builder()
.domainName("domain")
.redirectUriTemplate("http://localhost:8080/login/oauth2/code/")
.clientRegistrations(Collections.singletonList(second))
.build(),
OAuth2ClientsDomainParams.builder()
.domainName(UUID.randomUUID().toString())
.redirectUriTemplate("http://localhost:8080/login/oauth2/code/")
.clientRegistrations(Collections.singletonList(third))
.build()
))
@ -458,6 +464,7 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
.clientsDomainsParams(Arrays.asList(
OAuth2ClientsDomainParams.builder()
.domainName(UUID.randomUUID().toString())
.redirectUriTemplate("http://localhost:8080/login/oauth2/code/")
.clientRegistrations(Arrays.asList(first, second, third))
.build()
))
@ -471,20 +478,17 @@ public class BaseOAuth2ServiceTest extends AbstractServiceTest {
.allowUserCreation(true)
.activateUser(true)
.type(MapperType.CUSTOM)
.customConfig(
.custom(
OAuth2CustomMapperConfig.builder()
.url("localhost:8082")
.username("test")
.password("test")
.build()
)
.build())
.clientId("clientId")
.clientSecret("clientSecret")
.authorizationUri("authorizationUri")
.tokenUri("tokenUri")
.redirectUriTemplate("http://localhost:8080/login/oauth2/code/")
.scope("scope")
.accessTokenUri("tokenUri")
.scope(Arrays.asList("scope1", "scope2"))
.userInfoUri("userInfoUri")
.userNameAttributeName("userNameAttributeName")
.jwkSetUri("jwkSetUri")

Loading…
Cancel
Save