Added activate user config. Fixed https issue (#2737)
* Added activate user config. Fixed https issue * Update OAuth2User.java Co-authored-by: Igor Kulikov <ikulikov82@gmail.com>
This commit is contained in:
parent
f29c9c9452
commit
9b18c408b2
@ -204,11 +204,11 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
|
|||||||
http.oauth2Login()
|
http.oauth2Login()
|
||||||
.loginPage("/oauth2Login")
|
.loginPage("/oauth2Login")
|
||||||
.loginProcessingUrl(oauth2Configuration.getLoginProcessingUrl())
|
.loginProcessingUrl(oauth2Configuration.getLoginProcessingUrl())
|
||||||
.successHandler(oauth2AuthenticationSuccessHandler);
|
.successHandler(oauth2AuthenticationSuccessHandler)
|
||||||
|
.failureHandler(failureHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(CorsFilter.class)
|
@ConditionalOnMissingBean(CorsFilter.class)
|
||||||
public CorsFilter corsFilter(@Autowired MvcCorsProperties mvcCorsProperties) {
|
public CorsFilter corsFilter(@Autowired MvcCorsProperties mvcCorsProperties) {
|
||||||
|
|||||||
@ -52,6 +52,7 @@ 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.JwtToken;
|
||||||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
||||||
import org.thingsboard.server.service.security.system.SystemSecurityService;
|
import org.thingsboard.server.service.security.system.SystemSecurityService;
|
||||||
|
import org.thingsboard.server.utils.MiscUtils;
|
||||||
import ua_parser.Client;
|
import ua_parser.Client;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@ -170,7 +171,7 @@ public class AuthController extends BaseController {
|
|||||||
try {
|
try {
|
||||||
String email = resetPasswordByEmailRequest.get("email").asText();
|
String email = resetPasswordByEmailRequest.get("email").asText();
|
||||||
UserCredentials userCredentials = userService.requestPasswordReset(TenantId.SYS_TENANT_ID, email);
|
UserCredentials userCredentials = userService.requestPasswordReset(TenantId.SYS_TENANT_ID, email);
|
||||||
String baseUrl = constructBaseUrl(request);
|
String baseUrl = MiscUtils.constructBaseUrl(request);
|
||||||
String resetUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl,
|
String resetUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl,
|
||||||
userCredentials.getResetToken());
|
userCredentials.getResetToken());
|
||||||
|
|
||||||
@ -218,7 +219,7 @@ public class AuthController extends BaseController {
|
|||||||
User user = userService.findUserById(TenantId.SYS_TENANT_ID, credentials.getUserId());
|
User user = userService.findUserById(TenantId.SYS_TENANT_ID, credentials.getUserId());
|
||||||
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
|
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
|
||||||
SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
|
SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
|
||||||
String baseUrl = constructBaseUrl(request);
|
String baseUrl = MiscUtils.constructBaseUrl(request);
|
||||||
String loginUrl = String.format("%s/login", baseUrl);
|
String loginUrl = String.format("%s/login", baseUrl);
|
||||||
String email = user.getEmail();
|
String email = user.getEmail();
|
||||||
|
|
||||||
@ -265,7 +266,7 @@ public class AuthController extends BaseController {
|
|||||||
User user = userService.findUserById(TenantId.SYS_TENANT_ID, userCredentials.getUserId());
|
User user = userService.findUserById(TenantId.SYS_TENANT_ID, userCredentials.getUserId());
|
||||||
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
|
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
|
||||||
SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), principal);
|
SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), principal);
|
||||||
String baseUrl = constructBaseUrl(request);
|
String baseUrl = MiscUtils.constructBaseUrl(request);
|
||||||
String loginUrl = String.format("%s/login", baseUrl);
|
String loginUrl = String.format("%s/login", baseUrl);
|
||||||
String email = user.getEmail();
|
String email = user.getEmail();
|
||||||
mailService.sendPasswordWasResetEmail(loginUrl, email);
|
mailService.sendPasswordWasResetEmail(loginUrl, email);
|
||||||
|
|||||||
@ -521,39 +521,6 @@ public abstract class BaseController {
|
|||||||
return ruleNode;
|
return ruleNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected String constructBaseUrl(HttpServletRequest request) {
|
|
||||||
String scheme = request.getScheme();
|
|
||||||
|
|
||||||
String forwardedProto = request.getHeader("x-forwarded-proto");
|
|
||||||
if (forwardedProto != null) {
|
|
||||||
scheme = forwardedProto;
|
|
||||||
}
|
|
||||||
|
|
||||||
int serverPort = request.getServerPort();
|
|
||||||
if (request.getHeader("x-forwarded-port") != null) {
|
|
||||||
try {
|
|
||||||
serverPort = request.getIntHeader("x-forwarded-port");
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
}
|
|
||||||
} else if (forwardedProto != null) {
|
|
||||||
switch (forwardedProto) {
|
|
||||||
case "http":
|
|
||||||
serverPort = 80;
|
|
||||||
break;
|
|
||||||
case "https":
|
|
||||||
serverPort = 443;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String baseUrl = String.format("%s://%s:%d",
|
|
||||||
scheme,
|
|
||||||
request.getServerName(),
|
|
||||||
serverPort);
|
|
||||||
return baseUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected <I extends EntityId> I emptyId(EntityType entityType) {
|
protected <I extends EntityId> I emptyId(EntityType entityType) {
|
||||||
return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
|
return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,7 @@ import org.thingsboard.server.service.security.model.token.JwtToken;
|
|||||||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
||||||
import org.thingsboard.server.service.security.permission.Operation;
|
import org.thingsboard.server.service.security.permission.Operation;
|
||||||
import org.thingsboard.server.service.security.permission.Resource;
|
import org.thingsboard.server.service.security.permission.Resource;
|
||||||
|
import org.thingsboard.server.utils.MiscUtils;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
@ -148,7 +149,7 @@ public class UserController extends BaseController {
|
|||||||
if (sendEmail) {
|
if (sendEmail) {
|
||||||
SecurityUser authUser = getCurrentUser();
|
SecurityUser authUser = getCurrentUser();
|
||||||
UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), savedUser.getId());
|
UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), savedUser.getId());
|
||||||
String baseUrl = constructBaseUrl(request);
|
String baseUrl = MiscUtils.constructBaseUrl(request);
|
||||||
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
|
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
|
||||||
userCredentials.getActivateToken());
|
userCredentials.getActivateToken());
|
||||||
String email = savedUser.getEmail();
|
String email = savedUser.getEmail();
|
||||||
@ -188,7 +189,7 @@ public class UserController extends BaseController {
|
|||||||
|
|
||||||
UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId());
|
UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId());
|
||||||
if (!userCredentials.isEnabled()) {
|
if (!userCredentials.isEnabled()) {
|
||||||
String baseUrl = constructBaseUrl(request);
|
String baseUrl = MiscUtils.constructBaseUrl(request);
|
||||||
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
|
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
|
||||||
userCredentials.getActivateToken());
|
userCredentials.getActivateToken());
|
||||||
mailService.sendActivationEmail(activateUrl, email);
|
mailService.sendActivationEmail(activateUrl, email);
|
||||||
@ -213,7 +214,7 @@ public class UserController extends BaseController {
|
|||||||
SecurityUser authUser = getCurrentUser();
|
SecurityUser authUser = getCurrentUser();
|
||||||
UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), user.getId());
|
UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), user.getId());
|
||||||
if (!userCredentials.isEnabled()) {
|
if (!userCredentials.isEnabled()) {
|
||||||
String baseUrl = constructBaseUrl(request);
|
String baseUrl = MiscUtils.constructBaseUrl(request);
|
||||||
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
|
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
|
||||||
userCredentials.getActivateToken());
|
userCredentials.getActivateToken());
|
||||||
return activateUrl;
|
return activateUrl;
|
||||||
|
|||||||
@ -63,7 +63,7 @@ public abstract class AbstractOAuth2ClientMapper {
|
|||||||
|
|
||||||
private final Lock userCreationLock = new ReentrantLock();
|
private final Lock userCreationLock = new ReentrantLock();
|
||||||
|
|
||||||
protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, boolean allowUserCreation) {
|
protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, boolean allowUserCreation, boolean activateUser) {
|
||||||
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, oauth2User.getEmail());
|
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, oauth2User.getEmail());
|
||||||
|
|
||||||
User user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, oauth2User.getEmail());
|
User user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, oauth2User.getEmail());
|
||||||
@ -93,8 +93,10 @@ public abstract class AbstractOAuth2ClientMapper {
|
|||||||
user.setFirstName(oauth2User.getFirstName());
|
user.setFirstName(oauth2User.getFirstName());
|
||||||
user.setLastName(oauth2User.getLastName());
|
user.setLastName(oauth2User.getLastName());
|
||||||
user = userService.saveUser(user);
|
user = userService.saveUser(user);
|
||||||
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
|
if (activateUser) {
|
||||||
userService.activateUserCredentials(user.getTenantId(), userCredentials.getActivateToken(), passwordEncoder.encode(""));
|
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
|
||||||
|
userService.activateUserCredentials(user.getTenantId(), userCredentials.getActivateToken(), passwordEncoder.encode(""));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Can't get or create security user from oauth2 user", e);
|
log.error("Can't get or create security user from oauth2 user", e);
|
||||||
|
|||||||
@ -56,7 +56,8 @@ public class BasicOAuth2ClientMapper extends AbstractOAuth2ClientMapper implemen
|
|||||||
String customerName = sub.replace(config.getBasic().getCustomerNamePattern());
|
String customerName = sub.replace(config.getBasic().getCustomerNamePattern());
|
||||||
oauth2User.setCustomerName(customerName);
|
oauth2User.setCustomerName(customerName);
|
||||||
}
|
}
|
||||||
return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.getBasic().isAllowUserCreation());
|
|
||||||
|
return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.isAllowUserCreation(), config.isActivateUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getTenantName(Map<String, Object> attributes, OAuth2ClientMapperConfig config) {
|
private String getTenantName(Map<String, Object> attributes, OAuth2ClientMapperConfig config) {
|
||||||
|
|||||||
@ -38,7 +38,7 @@ public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme
|
|||||||
@Override
|
@Override
|
||||||
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig config) {
|
public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig config) {
|
||||||
OAuth2User oauth2User = getOAuth2User(token, config.getCustom());
|
OAuth2User oauth2User = getOAuth2User(token, config.getCustom());
|
||||||
return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.getBasic().isAllowUserCreation());
|
return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.isAllowUserCreation(), config.isActivateUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized OAuth2User getOAuth2User(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig.CustomOAuth2ClientMapperConfig custom) {
|
private synchronized OAuth2User getOAuth2User(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig.CustomOAuth2ClientMapperConfig custom) {
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
|
|||||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
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.JwtToken;
|
||||||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
||||||
|
import org.thingsboard.server.utils.MiscUtils;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
@ -65,6 +66,7 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
|
|||||||
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser);
|
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser);
|
||||||
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser);
|
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser);
|
||||||
|
|
||||||
getRedirectStrategy().sendRedirect(request, response, "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken());
|
String baseUrl = MiscUtils.constructBaseUrl(request);
|
||||||
|
getRedirectStrategy().sendRedirect(request, response, baseUrl + "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -18,8 +18,8 @@ package org.thingsboard.server.utils;
|
|||||||
import com.google.common.hash.HashFunction;
|
import com.google.common.hash.HashFunction;
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,4 +47,36 @@ public class MiscUtils {
|
|||||||
throw new IllegalArgumentException("Can't find hash function with name " + name);
|
throw new IllegalArgumentException("Can't find hash function with name " + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String constructBaseUrl(HttpServletRequest request) {
|
||||||
|
String scheme = request.getScheme();
|
||||||
|
|
||||||
|
String forwardedProto = request.getHeader("x-forwarded-proto");
|
||||||
|
if (forwardedProto != null) {
|
||||||
|
scheme = forwardedProto;
|
||||||
|
}
|
||||||
|
|
||||||
|
int serverPort = request.getServerPort();
|
||||||
|
if (request.getHeader("x-forwarded-port") != null) {
|
||||||
|
try {
|
||||||
|
serverPort = request.getIntHeader("x-forwarded-port");
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
} else if (forwardedProto != null) {
|
||||||
|
switch (forwardedProto) {
|
||||||
|
case "http":
|
||||||
|
serverPort = 80;
|
||||||
|
break;
|
||||||
|
case "https":
|
||||||
|
serverPort = 443;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String baseUrl = String.format("%s://%s:%d",
|
||||||
|
scheme,
|
||||||
|
request.getServerName(),
|
||||||
|
serverPort);
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -127,11 +127,13 @@ security:
|
|||||||
userInfoUri: "${SECURITY_OAUTH2_DEFAULT_USER_INFO_URI:}"
|
userInfoUri: "${SECURITY_OAUTH2_DEFAULT_USER_INFO_URI:}"
|
||||||
userNameAttributeName: "${SECURITY_OAUTH2_DEFAULT_USER_NAME_ATTRIBUTE_NAME:email}"
|
userNameAttributeName: "${SECURITY_OAUTH2_DEFAULT_USER_NAME_ATTRIBUTE_NAME:email}"
|
||||||
mapperConfig:
|
mapperConfig:
|
||||||
|
# Allows to create user if it not exists
|
||||||
|
allowUserCreation: "${SECURITY_OAUTH2_DEFAULT_MAPPER_ALLOW_USER_CREATION:true}"
|
||||||
|
# Allows user to setup ThingsBoard internal password and login over default Login window
|
||||||
|
activateUser: "${SECURITY_OAUTH2_DEFAULT_MAPPER_ACTIVATE_USER:false}"
|
||||||
# Mapper type of converter from external user into internal - 'basic' or 'custom'
|
# Mapper type of converter from external user into internal - 'basic' or 'custom'
|
||||||
type: "${SECURITY_OAUTH2_DEFAULT_MAPPER_TYPE:basic}"
|
type: "${SECURITY_OAUTH2_DEFAULT_MAPPER_TYPE:basic}"
|
||||||
basic:
|
basic:
|
||||||
# Allows to create user if it not exists
|
|
||||||
allowUserCreation: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_ALLOW_USER_CREATION:true}"
|
|
||||||
# Key from attributes of external user object to use as email
|
# Key from attributes of external user object to use as email
|
||||||
emailAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_EMAIL_ATTRIBUTE_KEY:email}"
|
emailAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_EMAIL_ATTRIBUTE_KEY:email}"
|
||||||
firstNameAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_FIRST_NAME_ATTRIBUTE_KEY:}"
|
firstNameAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_FIRST_NAME_ATTRIBUTE_KEY:}"
|
||||||
|
|||||||
@ -20,13 +20,14 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class OAuth2ClientMapperConfig {
|
public class OAuth2ClientMapperConfig {
|
||||||
|
|
||||||
|
private boolean allowUserCreation;
|
||||||
|
private boolean activateUser;
|
||||||
private String type;
|
private String type;
|
||||||
private BasicOAuth2ClientMapperConfig basic;
|
private BasicOAuth2ClientMapperConfig basic;
|
||||||
private CustomOAuth2ClientMapperConfig custom;
|
private CustomOAuth2ClientMapperConfig custom;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class BasicOAuth2ClientMapperConfig {
|
public static class BasicOAuth2ClientMapperConfig {
|
||||||
private boolean allowUserCreation;
|
|
||||||
private String emailAttributeKey;
|
private String emailAttributeKey;
|
||||||
private String firstNameAttributeKey;
|
private String firstNameAttributeKey;
|
||||||
private String lastNameAttributeKey;
|
private String lastNameAttributeKey;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user