16 changed files with 216 additions and 55 deletions
@ -0,0 +1,78 @@ |
|||
/** |
|||
* 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.util.StringUtils; |
|||
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig; |
|||
import org.thingsboard.server.dao.oauth2.OAuth2User; |
|||
|
|||
import java.util.Map; |
|||
|
|||
@Slf4j |
|||
public class BasicMapperUtils { |
|||
private static final String START_PLACEHOLDER_PREFIX = "%{"; |
|||
private static final String END_PLACEHOLDER_PREFIX = "}"; |
|||
|
|||
public static OAuth2User getOAuth2User(String email, Map<String, Object> attributes, OAuth2MapperConfig config) { |
|||
OAuth2User oauth2User = new OAuth2User(); |
|||
oauth2User.setEmail(email); |
|||
oauth2User.setTenantName(getTenantName(email, 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().getCustomerNamePattern())) { |
|||
StrSubstitutor sub = new StrSubstitutor(attributes, START_PLACEHOLDER_PREFIX, END_PLACEHOLDER_PREFIX); |
|||
String customerName = sub.replace(config.getBasic().getCustomerNamePattern()); |
|||
oauth2User.setCustomerName(customerName); |
|||
} |
|||
oauth2User.setAlwaysFullScreen(config.getBasic().isAlwaysFullScreen()); |
|||
if (!StringUtils.isEmpty(config.getBasic().getDefaultDashboardName())) { |
|||
oauth2User.setDefaultDashboardName(config.getBasic().getDefaultDashboardName()); |
|||
} |
|||
return oauth2User; |
|||
} |
|||
|
|||
public static String getTenantName(String email, Map<String, Object> attributes, OAuth2MapperConfig config) { |
|||
switch (config.getBasic().getTenantNameStrategy()) { |
|||
case EMAIL: |
|||
return email; |
|||
case DOMAIN: |
|||
return email.substring(email .indexOf("@") + 1); |
|||
case CUSTOM: |
|||
StrSubstitutor sub = new StrSubstitutor(attributes, START_PLACEHOLDER_PREFIX, END_PLACEHOLDER_PREFIX); |
|||
return sub.replace(config.getBasic().getTenantNamePattern()); |
|||
default: |
|||
throw new RuntimeException("Tenant Name Strategy with type " + config.getBasic().getTenantNameStrategy() + " is not supported!"); |
|||
} |
|||
} |
|||
|
|||
public static 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,91 @@ |
|||
/** |
|||
* 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.Data; |
|||
import lombok.ToString; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.boot.web.client.RestTemplateBuilder; |
|||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.web.client.RestTemplate; |
|||
import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig; |
|||
import org.thingsboard.server.dao.oauth2.OAuth2Configuration; |
|||
import org.thingsboard.server.dao.oauth2.OAuth2User; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Map; |
|||
import java.util.Optional; |
|||
|
|||
@Service(value = "githubOAuth2ClientMapper") |
|||
@Slf4j |
|||
public class GithubOAuth2ClientMapper extends AbstractOAuth2ClientMapper implements OAuth2ClientMapper { |
|||
private static final String EMAIL_URL_KEY = "emailUrl"; |
|||
|
|||
private static final String AUTHORIZATION = "Authorization"; |
|||
|
|||
private RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); |
|||
|
|||
@Autowired |
|||
private OAuth2Configuration oAuth2Configuration; |
|||
|
|||
@Override |
|||
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, String providerAccessToken, OAuth2MapperConfig config) { |
|||
Map<String, String> githubMapperConfig = oAuth2Configuration.getGithubMapper(); |
|||
String email = getEmail(githubMapperConfig.get(EMAIL_URL_KEY), providerAccessToken); |
|||
Map<String, Object> attributes = token.getPrincipal().getAttributes(); |
|||
OAuth2User oAuth2User = BasicMapperUtils.getOAuth2User(email, attributes, config); |
|||
return getOrCreateSecurityUserFromOAuth2User(oAuth2User, config.isAllowUserCreation(), config.isActivateUser()); |
|||
} |
|||
|
|||
private synchronized String getEmail(String emailUrl, String oauth2Token) { |
|||
restTemplateBuilder = restTemplateBuilder.defaultHeader(AUTHORIZATION, "token " + oauth2Token); |
|||
|
|||
RestTemplate restTemplate = restTemplateBuilder.build(); |
|||
GithubEmailsResponse githubEmailsResponse; |
|||
try { |
|||
githubEmailsResponse = restTemplate.getForEntity(emailUrl, GithubEmailsResponse.class).getBody(); |
|||
if (githubEmailsResponse == null){ |
|||
throw new RuntimeException("Empty Github response!"); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("There was an error during connection to Github API", e); |
|||
throw new RuntimeException("Unable to login. Please contact your Administrator!"); |
|||
} |
|||
Optional<String> emailOpt = githubEmailsResponse.stream() |
|||
.filter(GithubEmailResponse::isPrimary) |
|||
.map(GithubEmailResponse::getEmail) |
|||
.findAny(); |
|||
if (emailOpt.isPresent()){ |
|||
return emailOpt.get(); |
|||
} else { |
|||
log.error("Could not find primary email from {}.", githubEmailsResponse); |
|||
throw new RuntimeException("Unable to login. Please contact your Administrator!"); |
|||
} |
|||
} |
|||
private static class GithubEmailsResponse extends ArrayList<GithubEmailResponse> {} |
|||
|
|||
@Data |
|||
@ToString |
|||
private static class GithubEmailResponse { |
|||
private String email; |
|||
private boolean verified; |
|||
private boolean primary; |
|||
private String visibility; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue