committed by
Andrew Shvayka
30 changed files with 916 additions and 259 deletions
@ -1,81 +0,0 @@ |
|||||
/** |
|
||||
* 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.config; |
|
||||
|
|
||||
import org.springframework.beans.factory.annotation.Value; |
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|
||||
import org.springframework.context.annotation.Bean; |
|
||||
import org.springframework.context.annotation.Configuration; |
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration; |
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; |
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; |
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType; |
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod; |
|
||||
|
|
||||
import java.util.Collections; |
|
||||
|
|
||||
@ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true") |
|
||||
@Configuration |
|
||||
public class ThingsboardOAuth2Configuration { |
|
||||
|
|
||||
@Value("${security.oauth2.registrationId}") |
|
||||
private String registrationId; |
|
||||
@Value("${security.oauth2.userNameAttributeName}") |
|
||||
private String userNameAttributeName; |
|
||||
|
|
||||
@Value("${security.oauth2.client.clientId}") |
|
||||
private String clientId; |
|
||||
@Value("${security.oauth2.client.clientName}") |
|
||||
private String clientName; |
|
||||
@Value("${security.oauth2.client.clientSecret}") |
|
||||
private String clientSecret; |
|
||||
@Value("${security.oauth2.client.accessTokenUri}") |
|
||||
private String accessTokenUri; |
|
||||
@Value("${security.oauth2.client.authorizationUri}") |
|
||||
private String authorizationUri; |
|
||||
@Value("${security.oauth2.client.redirectUriTemplate}") |
|
||||
private String redirectUriTemplate; |
|
||||
@Value("${security.oauth2.client.scope}") |
|
||||
private String scope; |
|
||||
@Value("${security.oauth2.client.jwkSetUri}") |
|
||||
private String jwkSetUri; |
|
||||
@Value("${security.oauth2.client.authorizationGrantType}") |
|
||||
private String authorizationGrantType; |
|
||||
@Value("${security.oauth2.client.clientAuthenticationMethod}") |
|
||||
private String clientAuthenticationMethod; |
|
||||
|
|
||||
@Value("${security.oauth2.resource.userInfoUri}") |
|
||||
private String userInfoUri; |
|
||||
|
|
||||
@Bean |
|
||||
public ClientRegistrationRepository clientRegistrationRepository() { |
|
||||
ClientRegistration registration = ClientRegistration.withRegistrationId(registrationId) |
|
||||
.clientId(clientId) |
|
||||
.authorizationUri(authorizationUri) |
|
||||
.clientSecret(clientSecret) |
|
||||
.tokenUri(accessTokenUri) |
|
||||
.redirectUriTemplate(redirectUriTemplate) |
|
||||
.scope(scope.split(",")) |
|
||||
.clientName(clientName) |
|
||||
.authorizationGrantType(new AuthorizationGrantType(authorizationGrantType)) |
|
||||
.userInfoUri(userInfoUri) |
|
||||
.userNameAttributeName(userNameAttributeName) |
|
||||
.jwkSetUri(jwkSetUri) |
|
||||
.clientAuthenticationMethod(new ClientAuthenticationMethod(clientAuthenticationMethod)) |
|
||||
.build(); |
|
||||
return new InMemoryClientRegistrationRepository(Collections.singletonList(registration)); |
|
||||
} |
|
||||
} |
|
||||
@ -1,125 +0,0 @@ |
|||||
/** |
|
||||
* 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.service.security.auth.oauth; |
|
||||
|
|
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|
||||
import org.springframework.security.authentication.InsufficientAuthenticationException; |
|
||||
import org.springframework.security.authentication.LockedException; |
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
|
||||
import org.springframework.security.core.Authentication; |
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; |
|
||||
import org.springframework.stereotype.Component; |
|
||||
import org.thingsboard.server.common.data.User; |
|
||||
import org.thingsboard.server.common.data.id.TenantId; |
|
||||
import org.thingsboard.server.common.data.security.UserCredentials; |
|
||||
import org.thingsboard.server.dao.user.UserService; |
|
||||
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; |
|
||||
import org.thingsboard.server.service.security.model.SecurityUser; |
|
||||
import org.thingsboard.server.service.security.model.UserPrincipal; |
|
||||
import org.thingsboard.server.service.security.model.token.JwtToken; |
|
||||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory; |
|
||||
import org.thingsboard.server.service.security.system.SystemSecurityService; |
|
||||
|
|
||||
import javax.servlet.ServletException; |
|
||||
import javax.servlet.http.HttpServletRequest; |
|
||||
import javax.servlet.http.HttpServletResponse; |
|
||||
import java.io.IOException; |
|
||||
import java.util.HashMap; |
|
||||
import java.util.Map; |
|
||||
|
|
||||
@Component(value="oauth2AuthenticationSuccessHandler") |
|
||||
@ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true") |
|
||||
public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { |
|
||||
|
|
||||
private final ObjectMapper mapper; |
|
||||
private final JwtTokenFactory tokenFactory; |
|
||||
private final RefreshTokenRepository refreshTokenRepository; |
|
||||
private final SystemSecurityService systemSecurityService; |
|
||||
private final UserService userService; |
|
||||
|
|
||||
@Autowired |
|
||||
public Oauth2AuthenticationSuccessHandler(final ObjectMapper mapper, |
|
||||
final JwtTokenFactory tokenFactory, |
|
||||
final RefreshTokenRepository refreshTokenRepository, |
|
||||
final UserService userService, |
|
||||
final SystemSecurityService systemSecurityService) { |
|
||||
this.mapper = mapper; |
|
||||
this.tokenFactory = tokenFactory; |
|
||||
this.refreshTokenRepository = refreshTokenRepository; |
|
||||
this.userService = userService; |
|
||||
this.systemSecurityService = systemSecurityService; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { |
|
||||
Object object = authentication.getPrincipal(); |
|
||||
|
|
||||
System.out.println(object); |
|
||||
|
|
||||
// active user check
|
|
||||
|
|
||||
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, "tenant@thingsboard.org"); |
|
||||
SecurityUser securityUser = (SecurityUser) authenticateByUsernameAndPassword(principal,"tenant@thingsboard.org", "tenant").getPrincipal(); |
|
||||
|
|
||||
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); |
|
||||
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); |
|
||||
|
|
||||
Map<String, String> tokenMap = new HashMap<String, String>(); |
|
||||
tokenMap.put("token", accessToken.getToken()); |
|
||||
tokenMap.put("refreshToken", refreshToken.getToken()); |
|
||||
|
|
||||
// response.setStatus(HttpStatus.OK.value());
|
|
||||
// response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
|
||||
// mapper.writeValue(response.getWriter(), tokenMap);
|
|
||||
|
|
||||
request.setAttribute("token", accessToken.getToken()); |
|
||||
response.addHeader("token", accessToken.getToken()); |
|
||||
|
|
||||
getRedirectStrategy().sendRedirect(request, response, "http://localhost:4200/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken()); |
|
||||
} |
|
||||
|
|
||||
private Authentication authenticateByUsernameAndPassword(UserPrincipal userPrincipal, String username, String password) { |
|
||||
User user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, username); |
|
||||
if (user == null) { |
|
||||
throw new UsernameNotFoundException("User not found: " + username); |
|
||||
} |
|
||||
|
|
||||
try { |
|
||||
|
|
||||
UserCredentials userCredentials = userService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, user.getId()); |
|
||||
if (userCredentials == null) { |
|
||||
throw new UsernameNotFoundException("User credentials not found"); |
|
||||
} |
|
||||
|
|
||||
try { |
|
||||
systemSecurityService.validateUserCredentials(user.getTenantId(), userCredentials, username, password); |
|
||||
} catch (LockedException e) { |
|
||||
throw e; |
|
||||
} |
|
||||
|
|
||||
if (user.getAuthority() == null) |
|
||||
throw new InsufficientAuthenticationException("User has no authority assigned"); |
|
||||
|
|
||||
SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), userPrincipal); |
|
||||
return new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities()); |
|
||||
} catch (Exception e) { |
|
||||
throw e; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,112 @@ |
|||||
|
/** |
||||
|
* 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.service.security.auth.oauth2; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
import org.thingsboard.server.common.data.Customer; |
||||
|
import org.thingsboard.server.common.data.Tenant; |
||||
|
import org.thingsboard.server.common.data.User; |
||||
|
import org.thingsboard.server.common.data.id.CustomerId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.common.data.page.TextPageLink; |
||||
|
import org.thingsboard.server.common.data.security.Authority; |
||||
|
import org.thingsboard.server.dao.customer.CustomerService; |
||||
|
import org.thingsboard.server.dao.oauth2.OAuth2User; |
||||
|
import org.thingsboard.server.dao.tenant.TenantService; |
||||
|
import org.thingsboard.server.dao.user.UserService; |
||||
|
import org.thingsboard.server.service.security.model.SecurityUser; |
||||
|
import org.thingsboard.server.service.security.model.UserPrincipal; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Optional; |
||||
|
|
||||
|
@Slf4j |
||||
|
public abstract class BaseOAuth2ClientMapper { |
||||
|
|
||||
|
@Autowired |
||||
|
private UserService userService; |
||||
|
|
||||
|
@Autowired |
||||
|
private TenantService tenantService; |
||||
|
|
||||
|
@Autowired |
||||
|
private CustomerService customerService; |
||||
|
|
||||
|
protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, boolean allowUserCreation) { |
||||
|
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, oauth2User.getEmail()); |
||||
|
|
||||
|
User user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, oauth2User.getEmail()); |
||||
|
|
||||
|
if (user == null && !allowUserCreation) { |
||||
|
throw new UsernameNotFoundException("User not found: " + oauth2User.getEmail()); |
||||
|
} |
||||
|
|
||||
|
if (user == null) { |
||||
|
user = new User(); |
||||
|
if (StringUtils.isEmpty(oauth2User.getCustomerName())) { |
||||
|
user.setAuthority(Authority.TENANT_ADMIN); |
||||
|
} else { |
||||
|
user.setAuthority(Authority.CUSTOMER_USER); |
||||
|
} |
||||
|
user.setTenantId(getTenantId(oauth2User.getTenantName())); |
||||
|
user.setCustomerId(getCustomerId(user.getTenantId(), oauth2User.getCustomerName())); |
||||
|
user.setEmail(oauth2User.getEmail()); |
||||
|
user.setFirstName(oauth2User.getFirstName()); |
||||
|
user.setLastName(oauth2User.getLastName()); |
||||
|
user = userService.saveUser(user); |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
SecurityUser securityUser = new SecurityUser(user, true, principal); |
||||
|
return (SecurityUser) new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities()).getPrincipal(); |
||||
|
} catch (Exception e) { |
||||
|
log.error("Can't get or create security user from oauth2 user", e); |
||||
|
throw e; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private TenantId getTenantId(String tenantName) { |
||||
|
List<Tenant> tenants = tenantService.findTenants(new TextPageLink(1, tenantName)).getData(); |
||||
|
Tenant tenant; |
||||
|
if (tenants == null || tenants.isEmpty()) { |
||||
|
tenant = new Tenant(); |
||||
|
tenant.setTitle(tenantName); |
||||
|
tenant = tenantService.saveTenant(tenant); |
||||
|
} else { |
||||
|
tenant = tenants.get(0); |
||||
|
} |
||||
|
return tenant.getTenantId(); |
||||
|
} |
||||
|
|
||||
|
private CustomerId getCustomerId(TenantId tenantId, String customerName) { |
||||
|
if (StringUtils.isEmpty(customerName)) { |
||||
|
return null; |
||||
|
} |
||||
|
Optional<Customer> customerOpt = customerService.findCustomerByTenantIdAndTitle(tenantId, customerName); |
||||
|
if (customerOpt.isPresent()) { |
||||
|
return customerOpt.get().getId(); |
||||
|
} else { |
||||
|
Customer customer = new Customer(); |
||||
|
customer.setTenantId(tenantId); |
||||
|
customer.setTitle(customerName); |
||||
|
return customerService.saveCustomer(customer).getId(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
/** |
||||
|
* 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.service.security.auth.oauth2; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.commons.lang3.text.StrSubstitutor; |
||||
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
import org.thingsboard.server.dao.oauth2.OAuth2ClientMapperConfig; |
||||
|
import org.thingsboard.server.dao.oauth2.OAuth2User; |
||||
|
import org.thingsboard.server.service.security.model.SecurityUser; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Service(value = "basicOAuth2ClientMapper") |
||||
|
@Slf4j |
||||
|
public class BasicOAuth2ClientMapper extends BaseOAuth2ClientMapper implements OAuth2ClientMapper { |
||||
|
|
||||
|
@Override |
||||
|
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig config) { |
||||
|
OAuth2User oauth2User = new OAuth2User(); |
||||
|
Map<String, Object> attributes = token.getPrincipal().getAttributes(); |
||||
|
String email = getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey()); |
||||
|
oauth2User.setEmail(email); |
||||
|
oauth2User.setTenantName(getTenantName(attributes, config)); |
||||
|
if (!StringUtils.isEmpty(config.getBasic().getLastNameAttributeKey())) { |
||||
|
String lastName = getStringAttributeByKey(attributes, config.getBasic().getLastNameAttributeKey()); |
||||
|
oauth2User.setLastName(lastName); |
||||
|
} |
||||
|
if (!StringUtils.isEmpty(config.getBasic().getFirstNameAttributeKey())) { |
||||
|
String firstName = getStringAttributeByKey(attributes, config.getBasic().getFirstNameAttributeKey()); |
||||
|
oauth2User.setFirstName(firstName); |
||||
|
} |
||||
|
if (!StringUtils.isEmpty(config.getBasic().getCustomerNameStrategyPattern())) { |
||||
|
StrSubstitutor sub = new StrSubstitutor(attributes, "${", "}"); |
||||
|
String customerName = sub.replace(config.getBasic().getCustomerNameStrategyPattern()); |
||||
|
oauth2User.setCustomerName(customerName); |
||||
|
} |
||||
|
return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.getBasic().isAllowUserCreation()); |
||||
|
} |
||||
|
|
||||
|
private String getTenantName(Map<String, Object> attributes, OAuth2ClientMapperConfig config) { |
||||
|
switch (config.getBasic().getTenantNameStrategy()) { |
||||
|
case "domain": |
||||
|
String email = getStringAttributeByKey(attributes, config.getBasic().getEmailAttributeKey()); |
||||
|
return email.substring(email .indexOf("@") + 1); |
||||
|
case "custom": |
||||
|
StrSubstitutor sub = new StrSubstitutor(attributes, "${", "}"); |
||||
|
return sub.replace(config.getBasic().getTenantNameStrategyPattern()); |
||||
|
default: |
||||
|
throw new RuntimeException("Tenant Name Strategy with type " + config.getBasic().getTenantNameStrategy() + " is not supported!"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private String getStringAttributeByKey(Map<String, Object> attributes, String key) { |
||||
|
String result = null; |
||||
|
try { |
||||
|
result = (String) attributes.get(key); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.warn("Can't convert attribute to String by key " + key); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
/** |
||||
|
* 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.service.security.auth.oauth2; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.boot.web.client.RestTemplateBuilder; |
||||
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
import org.springframework.web.client.RestTemplate; |
||||
|
import org.thingsboard.server.dao.oauth2.OAuth2ClientMapperConfig; |
||||
|
import org.thingsboard.server.dao.oauth2.OAuth2User; |
||||
|
import org.thingsboard.server.service.security.model.SecurityUser; |
||||
|
|
||||
|
@Service(value = "customOAuth2ClientMapper") |
||||
|
@Slf4j |
||||
|
public class CustomOAuth2ClientMapper extends BaseOAuth2ClientMapper implements OAuth2ClientMapper { |
||||
|
|
||||
|
private RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); |
||||
|
|
||||
|
@Override |
||||
|
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig config) { |
||||
|
OAuth2User oauth2User = getOAuth2User(token, config.getCustom()); |
||||
|
return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.getBasic().isAllowUserCreation()); |
||||
|
} |
||||
|
|
||||
|
public OAuth2User getOAuth2User(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig.CustomOAuth2ClientMapperConfig custom) { |
||||
|
if (!StringUtils.isEmpty(custom.getUsername()) && !StringUtils.isEmpty(custom.getPassword())) { |
||||
|
restTemplateBuilder = restTemplateBuilder.basicAuthentication(custom.getUsername(), custom.getPassword()); |
||||
|
} |
||||
|
RestTemplate restTemplate = restTemplateBuilder.build(); |
||||
|
return restTemplate.postForEntity(custom.getUrl(), token.getPrincipal(), OAuth2User.class).getBody(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
/** |
||||
|
* 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.service.security.auth.oauth2; |
||||
|
|
||||
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; |
||||
|
import org.thingsboard.server.dao.oauth2.OAuth2ClientMapperConfig; |
||||
|
import org.thingsboard.server.service.security.model.SecurityUser; |
||||
|
|
||||
|
public interface OAuth2ClientMapper { |
||||
|
SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig config); |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
/** |
||||
|
* 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.service.security.auth.oauth2; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Qualifier; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
@Component |
||||
|
@Slf4j |
||||
|
public class OAuth2ClientMapperProvider { |
||||
|
|
||||
|
@Autowired |
||||
|
@Qualifier("basicOAuth2ClientMapper") |
||||
|
private OAuth2ClientMapper basicOAuth2ClientMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
@Qualifier("customOAuth2ClientMapper") |
||||
|
private OAuth2ClientMapper customOAuth2ClientMapper; |
||||
|
|
||||
|
public OAuth2ClientMapper getOAuth2ClientMapperByType(String oauth2ClientType) { |
||||
|
switch (oauth2ClientType) { |
||||
|
case "custom": |
||||
|
return customOAuth2ClientMapper; |
||||
|
case "basic": |
||||
|
return basicOAuth2ClientMapper; |
||||
|
default: |
||||
|
throw new RuntimeException("OAuth2ClientMapper with type " + oauth2ClientType + " is not supported!"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
/** |
||||
|
* 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.service.security.auth.oauth2; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||
|
import org.springframework.security.core.Authentication; |
||||
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; |
||||
|
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.thingsboard.server.dao.oauth2.OAuth2Client; |
||||
|
import org.thingsboard.server.dao.oauth2.OAuth2Configuration; |
||||
|
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; |
||||
|
import org.thingsboard.server.service.security.model.SecurityUser; |
||||
|
import org.thingsboard.server.service.security.model.token.JwtToken; |
||||
|
import org.thingsboard.server.service.security.model.token.JwtTokenFactory; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
|
||||
|
@Component(value = "oauth2AuthenticationSuccessHandler") |
||||
|
@ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true") |
||||
|
public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { |
||||
|
|
||||
|
private final JwtTokenFactory tokenFactory; |
||||
|
private final RefreshTokenRepository refreshTokenRepository; |
||||
|
private final OAuth2ClientMapperProvider oauth2ClientMapperProvider; |
||||
|
private final OAuth2Configuration oauth2Configuration; |
||||
|
|
||||
|
@Autowired |
||||
|
public Oauth2AuthenticationSuccessHandler(final JwtTokenFactory tokenFactory, |
||||
|
final RefreshTokenRepository refreshTokenRepository, |
||||
|
final OAuth2ClientMapperProvider oauth2ClientMapperProvider, |
||||
|
final OAuth2Configuration oauth2Configuration) { |
||||
|
this.tokenFactory = tokenFactory; |
||||
|
this.refreshTokenRepository = refreshTokenRepository; |
||||
|
this.oauth2ClientMapperProvider = oauth2ClientMapperProvider; |
||||
|
this.oauth2Configuration = oauth2Configuration; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onAuthenticationSuccess(HttpServletRequest request, |
||||
|
HttpServletResponse response, |
||||
|
Authentication authentication) throws IOException { |
||||
|
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication; |
||||
|
|
||||
|
OAuth2Client oauth2Client = oauth2Configuration.getClientByRegistrationId(token.getAuthorizedClientRegistrationId()); |
||||
|
OAuth2ClientMapper mapper = oauth2ClientMapperProvider.getOAuth2ClientMapperByType(oauth2Client.getMapperConfig().getType()); |
||||
|
SecurityUser securityUser = mapper.getOrCreateUserByClientPrincipal(token, oauth2Client.getMapperConfig()); |
||||
|
|
||||
|
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); |
||||
|
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); |
||||
|
|
||||
|
getRedirectStrategy().sendRedirect(request, response, "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
/** |
||||
|
* 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.dao.oauth2; |
||||
|
|
||||
|
import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public interface OAuth2Service { |
||||
|
|
||||
|
List<OAuth2ClientInfo> getOAuth2Clients(); |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
/** |
||||
|
* 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.dao.oauth2; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class OAuth2User { |
||||
|
private String tenantName; |
||||
|
private String customerName; |
||||
|
private String email; |
||||
|
private String firstName; |
||||
|
private String lastName; |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
/** |
||||
|
* 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.id; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonCreator; |
||||
|
import com.fasterxml.jackson.annotation.JsonProperty; |
||||
|
|
||||
|
import java.util.UUID; |
||||
|
|
||||
|
public class OAuth2IntegrationId extends UUIDBased { |
||||
|
|
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
@JsonCreator |
||||
|
public OAuth2IntegrationId(@JsonProperty("id") UUID id) { |
||||
|
super(id); |
||||
|
} |
||||
|
|
||||
|
public static OAuth2IntegrationId fromString(String oauth2IntegrationId) { |
||||
|
return new OAuth2IntegrationId(UUID.fromString(oauth2IntegrationId)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
/** |
||||
|
* 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; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import org.thingsboard.server.common.data.BaseData; |
||||
|
import org.thingsboard.server.common.data.id.OAuth2IntegrationId; |
||||
|
|
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@Data |
||||
|
public class OAuth2ClientInfo extends BaseData<OAuth2IntegrationId> { |
||||
|
|
||||
|
private String name; |
||||
|
private String icon; |
||||
|
private String url; |
||||
|
|
||||
|
public OAuth2ClientInfo() { |
||||
|
super(); |
||||
|
} |
||||
|
|
||||
|
public OAuth2ClientInfo(OAuth2IntegrationId id) { |
||||
|
super(id); |
||||
|
} |
||||
|
|
||||
|
public OAuth2ClientInfo(OAuth2ClientInfo oauth2ClientInfo) { |
||||
|
super(oauth2ClientInfo); |
||||
|
this.name = oauth2ClientInfo.getName(); |
||||
|
this.icon = oauth2ClientInfo.getIcon(); |
||||
|
this.url = oauth2ClientInfo.getUrl(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
/** |
||||
|
* 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.dao.oauth2; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class OAuth2Client { |
||||
|
|
||||
|
private String registrationId; |
||||
|
private String loginButtonLabel; |
||||
|
private String loginButtonIcon; |
||||
|
private String clientName; |
||||
|
private String clientId; |
||||
|
private String clientSecret; |
||||
|
private String accessTokenUri; |
||||
|
private String authorizationUri; |
||||
|
private String scope; |
||||
|
private String redirectUriTemplate; |
||||
|
private String jwkSetUri; |
||||
|
private String loginProcessingUrl; |
||||
|
private String authorizationGrantType; |
||||
|
private String clientAuthenticationMethod; |
||||
|
private String userInfoUri; |
||||
|
private String userNameAttributeName; |
||||
|
private OAuth2ClientMapperConfig mapperConfig; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
/** |
||||
|
* 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.dao.oauth2; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class OAuth2ClientMapperConfig { |
||||
|
|
||||
|
private String type; |
||||
|
private CustomOAuth2ClientMapperConfig custom; |
||||
|
private BasicOAuth2ClientMapperConfig basic; |
||||
|
|
||||
|
@Data |
||||
|
public static class BasicOAuth2ClientMapperConfig { |
||||
|
private boolean allowUserCreation; |
||||
|
private String emailAttributeKey; |
||||
|
private String firstNameAttributeKey; |
||||
|
private String lastNameAttributeKey; |
||||
|
private String tenantNameStrategy; |
||||
|
private String tenantNameStrategyPattern; |
||||
|
private String customerNameStrategyPattern; |
||||
|
} |
||||
|
|
||||
|
@Data |
||||
|
public static class CustomOAuth2ClientMapperConfig { |
||||
|
private String url; |
||||
|
private String username; |
||||
|
private String password; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
/** |
||||
|
* 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.dao.oauth2; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.security.oauth2.client.registration.ClientRegistration; |
||||
|
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; |
||||
|
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; |
||||
|
import org.springframework.security.oauth2.core.AuthorizationGrantType; |
||||
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Configuration |
||||
|
@ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true", matchIfMissing = true) |
||||
|
@ConfigurationProperties(prefix = "security.oauth2") |
||||
|
@Data |
||||
|
@Slf4j |
||||
|
public class OAuth2Configuration { |
||||
|
|
||||
|
private boolean enabled; |
||||
|
private Map<String, OAuth2Client> clients = new HashMap<>(); |
||||
|
|
||||
|
@Bean |
||||
|
public ClientRegistrationRepository clientRegistrationRepository() { |
||||
|
List<ClientRegistration> result = new ArrayList<>(); |
||||
|
for (OAuth2Client client : clients.values()) { |
||||
|
ClientRegistration registration = ClientRegistration.withRegistrationId(client.getRegistrationId()) |
||||
|
.clientId(client.getClientId()) |
||||
|
.authorizationUri(client.getAuthorizationUri()) |
||||
|
.clientSecret(client.getClientSecret()) |
||||
|
.tokenUri(client.getAccessTokenUri()) |
||||
|
.redirectUriTemplate(client.getRedirectUriTemplate()) |
||||
|
.scope(client.getScope().split(",")) |
||||
|
.clientName(client.getClientName()) |
||||
|
.authorizationGrantType(new AuthorizationGrantType(client.getAuthorizationGrantType())) |
||||
|
.userInfoUri(client.getUserInfoUri()) |
||||
|
.userNameAttributeName(client.getUserNameAttributeName()) |
||||
|
.jwkSetUri(client.getJwkSetUri()) |
||||
|
.clientAuthenticationMethod(new ClientAuthenticationMethod(client.getClientAuthenticationMethod())) |
||||
|
.build(); |
||||
|
result.add(registration); |
||||
|
} |
||||
|
return new InMemoryClientRegistrationRepository(result); |
||||
|
} |
||||
|
|
||||
|
public OAuth2Client getClientByRegistrationId(String registrationId) { |
||||
|
OAuth2Client result = null; |
||||
|
if (clients != null && !clients.isEmpty()) { |
||||
|
for (OAuth2Client client : clients.values()) { |
||||
|
if (client.getRegistrationId().equals(registrationId)) { |
||||
|
result = client; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
/** |
||||
|
* 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.dao.oauth2; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@Slf4j |
||||
|
@Service |
||||
|
public class OAuth2ServiceImpl implements OAuth2Service { |
||||
|
|
||||
|
@Autowired(required = false) |
||||
|
OAuth2Configuration oauth2Configuration; |
||||
|
|
||||
|
@Override |
||||
|
public List<OAuth2ClientInfo> getOAuth2Clients() { |
||||
|
if (!oauth2Configuration.isEnabled()) { |
||||
|
return Collections.emptyList(); |
||||
|
} |
||||
|
List<OAuth2ClientInfo> result = new ArrayList<>(); |
||||
|
for (OAuth2Client c : oauth2Configuration.getClients().values()) { |
||||
|
OAuth2ClientInfo client = new OAuth2ClientInfo(); |
||||
|
client.setName(c.getLoginButtonLabel()); |
||||
|
client.setUrl(String.format("/oauth2/authorization/%s", c.getRegistrationId())); |
||||
|
client.setIcon(c.getLoginButtonIcon()); |
||||
|
result.add(client); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue