Allow to pass several domains for oauth2 config (for sys_admin only)
This commit is contained in:
parent
997821591a
commit
d22237796e
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* 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.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@Data
|
||||||
|
@ToString
|
||||||
|
@Builder(toBuilder = true)
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class OAuth2ClientsDomainParams {
|
||||||
|
private String domainName;
|
||||||
|
private String adminSettingsId;
|
||||||
|
|
||||||
|
private List<OAuth2ClientRegistration> clientRegistrations;
|
||||||
|
}
|
||||||
@ -26,8 +26,5 @@ import java.util.List;
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class OAuth2ClientsParams {
|
public class OAuth2ClientsParams {
|
||||||
private String domainName;
|
private List<OAuth2ClientsDomainParams> clientsDomainsParams;
|
||||||
private String adminSettingsId;
|
|
||||||
|
|
||||||
private List<OAuth2ClientRegistration> clientRegistrations;
|
|
||||||
}
|
}
|
||||||
@ -47,6 +47,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -79,7 +80,6 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
return environment.acceptsProfiles("install");
|
return environment.acceptsProfiles("install");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO do I need to add a field that invalidates cache in case write to cache fails after successful saving in DB?
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
if (isInstall()) return;
|
if (isInstall()) return;
|
||||||
@ -94,7 +94,7 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
return clientsParams.entrySet().stream()
|
return clientsParams.entrySet().stream()
|
||||||
.map(entry -> {
|
.map(entry -> {
|
||||||
TenantId tenantId = entry.getKey();
|
TenantId tenantId = entry.getKey();
|
||||||
OAuth2ClientRegistration clientRegistration = entry.getValue().getClientRegistrations().stream()
|
OAuth2ClientRegistration clientRegistration = toClientRegistrationStream(entry.getValue())
|
||||||
.filter(registration -> registrationId.equals(registration.getRegistrationId()))
|
.filter(registration -> registrationId.equals(registration.getRegistrationId()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
@ -115,9 +115,9 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<OAuth2ClientInfo> getOAuth2Clients(String domainName) {
|
public List<OAuth2ClientInfo> getOAuth2Clients(String domainName) {
|
||||||
OAuth2ClientsParams oAuth2ClientsParams = getMergedOAuth2ClientsParams(domainName);
|
OAuth2ClientsDomainParams oAuth2ClientsDomainParams = getMergedOAuth2ClientsParams(domainName);
|
||||||
return oAuth2ClientsParams != null && oAuth2ClientsParams.getClientRegistrations() != null ?
|
return oAuth2ClientsDomainParams != null && oAuth2ClientsDomainParams.getClientRegistrations() != null ?
|
||||||
oAuth2ClientsParams.getClientRegistrations().stream()
|
oAuth2ClientsDomainParams.getClientRegistrations().stream()
|
||||||
.map(this::toClientInfo)
|
.map(this::toClientInfo)
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
: Collections.emptyList()
|
: Collections.emptyList()
|
||||||
@ -150,15 +150,19 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2ClientsParams saveTenantOAuth2ClientsParams(TenantId tenantId, OAuth2ClientsParams oAuth2ClientsParams) {
|
public OAuth2ClientsParams saveTenantOAuth2ClientsParams(TenantId tenantId, OAuth2ClientsParams oAuth2ClientsParams) {
|
||||||
// TODO what if tenant saves config for several different domain names, do we need to check it
|
if (oAuth2ClientsParams.getClientsDomainsParams().size() != 1) {
|
||||||
|
throw new DataValidationException("Tenant can configure OAuth2 only for one domain!");
|
||||||
|
}
|
||||||
validate(oAuth2ClientsParams);
|
validate(oAuth2ClientsParams);
|
||||||
|
|
||||||
validateRegistrationIdUniqueness(oAuth2ClientsParams, tenantId);
|
validateRegistrationIdUniqueness(oAuth2ClientsParams, tenantId);
|
||||||
cacheWriteLock.lock();
|
cacheWriteLock.lock();
|
||||||
try {
|
try {
|
||||||
validateRegistrationIdUniqueness(oAuth2ClientsParams, tenantId);
|
validateRegistrationIdUniqueness(oAuth2ClientsParams, tenantId);
|
||||||
String adminSettingsId = processTenantAdminSettings(tenantId, oAuth2ClientsParams.getDomainName(), oAuth2ClientsParams.getAdminSettingsId());
|
|
||||||
oAuth2ClientsParams.setAdminSettingsId(adminSettingsId);
|
OAuth2ClientsDomainParams oAuth2ClientsDomainParams = oAuth2ClientsParams.getClientsDomainsParams().get(0);
|
||||||
|
String adminSettingsId = processTenantAdminSettings(tenantId, oAuth2ClientsDomainParams.getDomainName(), oAuth2ClientsDomainParams.getAdminSettingsId());
|
||||||
|
oAuth2ClientsDomainParams.setAdminSettingsId(adminSettingsId);
|
||||||
|
|
||||||
List<AttributeKvEntry> attributes = createOAuth2ClientsParamsAttributes(oAuth2ClientsParams);
|
List<AttributeKvEntry> attributes = createOAuth2ClientsParamsAttributes(oAuth2ClientsParams);
|
||||||
try {
|
try {
|
||||||
@ -247,11 +251,20 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void validateRegistrationIdUniqueness(OAuth2ClientsParams inputOAuth2ClientsParams, TenantId tenantId) {
|
private void validateRegistrationIdUniqueness(OAuth2ClientsParams inputOAuth2ClientsParams, TenantId tenantId) {
|
||||||
inputOAuth2ClientsParams.getClientRegistrations().stream()
|
long distinctRegistrationIds = toClientRegistrationStream(inputOAuth2ClientsParams)
|
||||||
|
.map(OAuth2ClientRegistration::getRegistrationId)
|
||||||
|
.distinct()
|
||||||
|
.count();
|
||||||
|
long actualRegistrationIds = toClientRegistrationStream(inputOAuth2ClientsParams).count();
|
||||||
|
if (distinctRegistrationIds != actualRegistrationIds) {
|
||||||
|
throw new DataValidationException("All registration IDs should be unique!");
|
||||||
|
}
|
||||||
|
|
||||||
|
toClientRegistrationStream(inputOAuth2ClientsParams)
|
||||||
.map(OAuth2ClientRegistration::getRegistrationId)
|
.map(OAuth2ClientRegistration::getRegistrationId)
|
||||||
.forEach(registrationId -> {
|
.forEach(registrationId -> {
|
||||||
clientsParams.forEach((paramsTenantId, oAuth2ClientsParams) -> {
|
clientsParams.forEach((paramsTenantId, oAuth2ClientsParams) -> {
|
||||||
boolean registrationExists = oAuth2ClientsParams.getClientRegistrations().stream()
|
boolean registrationExists = toClientRegistrationStream(oAuth2ClientsParams)
|
||||||
.map(OAuth2ClientRegistration::getRegistrationId)
|
.map(OAuth2ClientRegistration::getRegistrationId)
|
||||||
.anyMatch(registrationId::equals);
|
.anyMatch(registrationId::equals);
|
||||||
if (registrationExists && !tenantId.equals(paramsTenantId)) {
|
if (registrationExists && !tenantId.equals(paramsTenantId)) {
|
||||||
@ -263,8 +276,27 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void validate(OAuth2ClientsParams oAuth2ClientsParams) {
|
private void validate(OAuth2ClientsParams oAuth2ClientsParams) {
|
||||||
for (OAuth2ClientRegistration clientRegistration : oAuth2ClientsParams.getClientRegistrations()) {
|
validateDomainNames(oAuth2ClientsParams);
|
||||||
validator.accept(clientRegistration);
|
|
||||||
|
toClientRegistrationStream(oAuth2ClientsParams)
|
||||||
|
.forEach(validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateDomainNames(OAuth2ClientsParams oAuth2ClientsParams) {
|
||||||
|
oAuth2ClientsParams.getClientsDomainsParams()
|
||||||
|
.forEach(oAuth2ClientsDomainParams -> {
|
||||||
|
if (StringUtils.isEmpty(oAuth2ClientsDomainParams.getDomainName())) {
|
||||||
|
throw new DataValidationException("Domain name should be specified!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
long distinctDomainNames = oAuth2ClientsParams.getClientsDomainsParams().stream()
|
||||||
|
.map(OAuth2ClientsDomainParams::getDomainName)
|
||||||
|
.distinct()
|
||||||
|
.count();
|
||||||
|
long actualDomainNames = oAuth2ClientsParams.getClientsDomainsParams().size();
|
||||||
|
if (distinctDomainNames != actualDomainNames) {
|
||||||
|
throw new DataValidationException("All domain names should be unique!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,7 +332,9 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
entry -> constructOAuth2ClientsParams(entry.getValue())
|
entry -> constructOAuth2ClientsParams(entry.getValue())
|
||||||
))
|
))
|
||||||
: new HashMap<>();
|
: new HashMap<>();
|
||||||
|
if (systemOAuth2ClientsParams.getClientsDomainsParams() != null) {
|
||||||
tenantClientParams.put(TenantId.SYS_TENANT_ID, systemOAuth2ClientsParams);
|
tenantClientParams.put(TenantId.SYS_TENANT_ID, systemOAuth2ClientsParams);
|
||||||
|
}
|
||||||
return tenantClientParams;
|
return tenantClientParams;
|
||||||
},
|
},
|
||||||
MoreExecutors.directExecutor()
|
MoreExecutors.directExecutor()
|
||||||
@ -314,13 +348,13 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
@Override
|
@Override
|
||||||
public void deleteTenantOAuth2ClientsParams(TenantId tenantId) {
|
public void deleteTenantOAuth2ClientsParams(TenantId tenantId) {
|
||||||
OAuth2ClientsParams params = getTenantOAuth2ClientsParams(tenantId);
|
OAuth2ClientsParams params = getTenantOAuth2ClientsParams(tenantId);
|
||||||
if (!StringUtils.isEmpty(params.getDomainName())) {
|
if (params == null) return;
|
||||||
String settingsKey = constructAdminSettingsDomainKey(params.getDomainName());
|
OAuth2ClientsDomainParams domainParams = params.getClientsDomainsParams().get(0);
|
||||||
|
String settingsKey = constructAdminSettingsDomainKey(domainParams.getDomainName());
|
||||||
adminSettingsService.deleteAdminSettingsByKey(tenantId, settingsKey);
|
adminSettingsService.deleteAdminSettingsByKey(tenantId, settingsKey);
|
||||||
attributesService.removeAll(tenantId, tenantId, DataConstants.SERVER_SCOPE, Collections.singletonList(OAUTH2_CLIENT_REGISTRATIONS_PARAMS));
|
attributesService.removeAll(tenantId, tenantId, DataConstants.SERVER_SCOPE, Collections.singletonList(OAUTH2_CLIENT_REGISTRATIONS_PARAMS));
|
||||||
clientsParams.remove(tenantId);
|
clientsParams.remove(tenantId);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOAuth2ClientRegistrationAllowed(TenantId tenantId) {
|
public boolean isOAuth2ClientRegistrationAllowed(TenantId tenantId) {
|
||||||
@ -351,9 +385,17 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
}, MoreExecutors.directExecutor());
|
}, MoreExecutors.directExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
private OAuth2ClientsParams getMergedOAuth2ClientsParams(String domainName) {
|
private OAuth2ClientsDomainParams getMergedOAuth2ClientsParams(String domainName) {
|
||||||
AdminSettings oauth2ClientsSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, constructAdminSettingsDomainKey(domainName));
|
AdminSettings oauth2ClientsSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, constructAdminSettingsDomainKey(domainName));
|
||||||
OAuth2ClientsParams result;
|
OAuth2ClientsDomainParams result;
|
||||||
|
|
||||||
|
OAuth2ClientsParams systemOAuth2ClientsParams = getSystemOAuth2ClientsParams(TenantId.SYS_TENANT_ID);
|
||||||
|
OAuth2ClientsDomainParams systemOAuth2ClientsDomainParams = systemOAuth2ClientsParams != null ?
|
||||||
|
systemOAuth2ClientsParams.getClientsDomainsParams().stream()
|
||||||
|
.filter(oAuth2ClientsDomainParams -> domainName.equals(oAuth2ClientsDomainParams.getDomainName()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null)
|
||||||
|
: null;
|
||||||
if (oauth2ClientsSettings != null) {
|
if (oauth2ClientsSettings != null) {
|
||||||
String strEntityType = oauth2ClientsSettings.getJsonValue().get("entityType").asText();
|
String strEntityType = oauth2ClientsSettings.getJsonValue().get("entityType").asText();
|
||||||
String strEntityId = oauth2ClientsSettings.getJsonValue().get("entityId").asText();
|
String strEntityId = oauth2ClientsSettings.getJsonValue().get("entityId").asText();
|
||||||
@ -363,17 +405,16 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
throw new IllegalStateException("Only tenant can configure OAuth2 for certain domain!");
|
throw new IllegalStateException("Only tenant can configure OAuth2 for certain domain!");
|
||||||
}
|
}
|
||||||
TenantId tenantId = (TenantId) entityId;
|
TenantId tenantId = (TenantId) entityId;
|
||||||
result = getTenantOAuth2ClientsParams(tenantId);
|
result = getTenantOAuth2ClientsParams(tenantId).getClientsDomainsParams().get(0);
|
||||||
OAuth2ClientsParams systemOAuth2ClientsParams = getSystemOAuth2ClientsParams(TenantId.SYS_TENANT_ID);
|
if (systemOAuth2ClientsDomainParams != null) {
|
||||||
if (systemOAuth2ClientsParams != null) {
|
|
||||||
ArrayList<OAuth2ClientRegistration> tenantClientRegistrations = new ArrayList<>(result.getClientRegistrations());
|
ArrayList<OAuth2ClientRegistration> tenantClientRegistrations = new ArrayList<>(result.getClientRegistrations());
|
||||||
tenantClientRegistrations.addAll(systemOAuth2ClientsParams.getClientRegistrations());
|
tenantClientRegistrations.addAll(systemOAuth2ClientsDomainParams.getClientRegistrations());
|
||||||
result = result.toBuilder()
|
result = result.toBuilder()
|
||||||
.clientRegistrations(tenantClientRegistrations)
|
.clientRegistrations(tenantClientRegistrations)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = getSystemOAuth2ClientsParams(TenantId.SYS_TENANT_ID);
|
result = systemOAuth2ClientsDomainParams;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -423,6 +464,11 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Stream<OAuth2ClientRegistration> toClientRegistrationStream(OAuth2ClientsParams oAuth2ClientsParams) {
|
||||||
|
return oAuth2ClientsParams.getClientsDomainsParams().stream()
|
||||||
|
.flatMap(oAuth2ClientsDomainParams -> oAuth2ClientsDomainParams.getClientRegistrations().stream());
|
||||||
|
}
|
||||||
|
|
||||||
private final Consumer<OAuth2ClientRegistration> validator = clientRegistration -> {
|
private final Consumer<OAuth2ClientRegistration> validator = clientRegistration -> {
|
||||||
if (StringUtils.isEmpty(clientRegistration.getRegistrationId())) {
|
if (StringUtils.isEmpty(clientRegistration.getRegistrationId())) {
|
||||||
throw new DataValidationException("Registration ID should be specified!");
|
throw new DataValidationException("Registration ID should be specified!");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user