Added generation an audit log for oauth2 login and with which provider was done an authorization
This commit is contained in:
parent
d7aa2e5660
commit
126d7215c5
@ -59,7 +59,6 @@ import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
import org.thingsboard.server.service.security.model.UserPrincipal;
|
||||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
||||
import org.thingsboard.server.service.security.system.SystemSecurityService;
|
||||
import ua_parser.Client;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.URI;
|
||||
@ -324,49 +323,7 @@ public class AuthController extends BaseController {
|
||||
|
||||
private void logLogoutAction(HttpServletRequest request) throws ThingsboardException {
|
||||
try {
|
||||
SecurityUser user = getCurrentUser();
|
||||
RestAuthenticationDetails details = new RestAuthenticationDetails(request);
|
||||
String clientAddress = details.getClientAddress();
|
||||
String browser = "Unknown";
|
||||
String os = "Unknown";
|
||||
String device = "Unknown";
|
||||
if (details.getUserAgent() != null) {
|
||||
Client userAgent = details.getUserAgent();
|
||||
if (userAgent.userAgent != null) {
|
||||
browser = userAgent.userAgent.family;
|
||||
if (userAgent.userAgent.major != null) {
|
||||
browser += " " + userAgent.userAgent.major;
|
||||
if (userAgent.userAgent.minor != null) {
|
||||
browser += "." + userAgent.userAgent.minor;
|
||||
if (userAgent.userAgent.patch != null) {
|
||||
browser += "." + userAgent.userAgent.patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (userAgent.os != null) {
|
||||
os = userAgent.os.family;
|
||||
if (userAgent.os.major != null) {
|
||||
os += " " + userAgent.os.major;
|
||||
if (userAgent.os.minor != null) {
|
||||
os += "." + userAgent.os.minor;
|
||||
if (userAgent.os.patch != null) {
|
||||
os += "." + userAgent.os.patch;
|
||||
if (userAgent.os.patchMinor != null) {
|
||||
os += "." + userAgent.os.patchMinor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (userAgent.device != null) {
|
||||
device = userAgent.device.family;
|
||||
}
|
||||
}
|
||||
auditLogService.logEntityAction(
|
||||
user.getTenantId(), user.getCustomerId(), user.getId(),
|
||||
user.getName(), user.getId(), null, ActionType.LOGOUT, null, clientAddress, browser, os, device);
|
||||
|
||||
systemSecurityService.logLoginAction(getCurrentUser(), new RestAuthenticationDetails(request), ActionType.LOGOUT, null, "REST");
|
||||
} catch (Exception e) {
|
||||
throw handleException(e);
|
||||
}
|
||||
|
||||
@ -58,6 +58,8 @@ import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
|
||||
@RequiredArgsConstructor
|
||||
public class TwoFactorAuthController extends BaseController {
|
||||
|
||||
private static final String TwoFA_PROVIDER = "2FA ";
|
||||
|
||||
private final TwoFactorAuthService twoFactorAuthService;
|
||||
private final TwoFaConfigManager twoFaConfigManager;
|
||||
private final JwtTokenFactory tokenFactory;
|
||||
@ -92,12 +94,12 @@ public class TwoFactorAuthController extends BaseController {
|
||||
SecurityUser user = getCurrentUser();
|
||||
boolean verificationSuccess = twoFactorAuthService.checkVerificationCode(user, providerType, verificationCode, true);
|
||||
if (verificationSuccess) {
|
||||
systemSecurityService.logLoginAction(user, new RestAuthenticationDetails(servletRequest), ActionType.LOGIN, null);
|
||||
systemSecurityService.logLoginAction(user, new RestAuthenticationDetails(servletRequest), ActionType.LOGIN, null, TwoFA_PROVIDER + providerType);
|
||||
user = new SecurityUser(userService.findUserById(user.getTenantId(), user.getId()), true, user.getUserPrincipal());
|
||||
return tokenFactory.createTokenPair(user);
|
||||
} else {
|
||||
ThingsboardException error = new ThingsboardException("Verification code is incorrect", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
|
||||
systemSecurityService.logLoginAction(user, new RestAuthenticationDetails(servletRequest), ActionType.LOGIN, error);
|
||||
systemSecurityService.logLoginAction(user, new RestAuthenticationDetails(servletRequest), ActionType.LOGIN, error, TwoFA_PROVIDER + providerType);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequ
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.common.data.StringUtils;
|
||||
import org.thingsboard.server.common.data.audit.ActionType;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
@ -33,6 +34,7 @@ import org.thingsboard.server.common.data.security.model.JwtToken;
|
||||
import org.thingsboard.server.dao.oauth2.OAuth2Service;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
|
||||
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
|
||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
||||
import org.thingsboard.server.service.security.system.SystemSecurityService;
|
||||
@ -102,6 +104,7 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
|
||||
|
||||
clearAuthenticationAttributes(request, response);
|
||||
getRedirectStrategy().sendRedirect(request, response, baseUrl + "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken());
|
||||
systemSecurityService.logLoginAction(securityUser, new RestAuthenticationDetails(request), ActionType.LOGIN, null, "OAUTH2: " + registration.getName());
|
||||
} catch (Exception e) {
|
||||
log.debug("Error occurred during processing authentication success result. " +
|
||||
"request [{}], response [{}], authentication [{}]", request, response, authentication, e);
|
||||
|
||||
@ -53,6 +53,8 @@ import java.util.UUID;
|
||||
@TbCoreComponent
|
||||
public class RestAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private static final String REST_PROVIDER = "REST";
|
||||
|
||||
private final SystemSecurityService systemSecurityService;
|
||||
private final UserService userService;
|
||||
private final CustomerService customerService;
|
||||
@ -87,7 +89,7 @@ public class RestAuthenticationProvider implements AuthenticationProvider {
|
||||
if (twoFactorAuthService.isTwoFaEnabled(securityUser.getTenantId(), securityUser.getId())) {
|
||||
return new MfaAuthenticationToken(securityUser);
|
||||
} else {
|
||||
systemSecurityService.logLoginAction(securityUser, authentication.getDetails(), ActionType.LOGIN, null);
|
||||
systemSecurityService.logLoginAction(securityUser, authentication.getDetails(), ActionType.LOGIN, null, REST_PROVIDER);
|
||||
}
|
||||
} else {
|
||||
String publicId = userPrincipal.getValue();
|
||||
@ -113,7 +115,7 @@ public class RestAuthenticationProvider implements AuthenticationProvider {
|
||||
try {
|
||||
systemSecurityService.validateUserCredentials(user.getTenantId(), userCredentials, username, password);
|
||||
} catch (LockedException e) {
|
||||
systemSecurityService.logLoginAction(user, authentication.getDetails(), ActionType.LOCKOUT, null);
|
||||
systemSecurityService.logLoginAction(user, authentication.getDetails(), ActionType.LOCKOUT, null, REST_PROVIDER);
|
||||
throw e;
|
||||
}
|
||||
|
||||
@ -122,7 +124,7 @@ public class RestAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
return new SecurityUser(user, userCredentials.isEnabled(), userPrincipal);
|
||||
} catch (Exception e) {
|
||||
systemSecurityService.logLoginAction(user, authentication.getDetails(), ActionType.LOGIN, e);
|
||||
systemSecurityService.logLoginAction(user, authentication.getDetails(), ActionType.LOGIN, e, REST_PROVIDER);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,8 +59,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
|
||||
import org.thingsboard.server.service.security.exception.UserPasswordExpiredException;
|
||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
import org.thingsboard.server.utils.AuthorizationDetails;
|
||||
import org.thingsboard.server.utils.MiscUtils;
|
||||
import ua_parser.Client;
|
||||
import org.thingsboard.server.utils.RestAuthenticationDetailsUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@ -232,7 +233,8 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
||||
JsonNode additionalInfo = user.getAdditionalInfo();
|
||||
if (additionalInfo instanceof ObjectNode && additionalInfo.has(UserServiceImpl.USER_PASSWORD_HISTORY)) {
|
||||
JsonNode userPasswordHistoryJson = additionalInfo.get(UserServiceImpl.USER_PASSWORD_HISTORY);
|
||||
Map<String, String> userPasswordHistoryMap = JacksonUtil.convertValue(userPasswordHistoryJson, new TypeReference<>() {});
|
||||
Map<String, String> userPasswordHistoryMap = JacksonUtil.convertValue(userPasswordHistoryJson, new TypeReference<>() {
|
||||
});
|
||||
for (Map.Entry<String, String> entry : userPasswordHistoryMap.entrySet()) {
|
||||
if (encoder.matches(password, entry.getValue()) && Long.parseLong(entry.getKey()) > passwordReuseFrequencyTs) {
|
||||
throw new DataValidationException("Password was already used for the last " + passwordPolicy.getPasswordReuseFrequencyDays() + " days");
|
||||
@ -262,54 +264,24 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logLoginAction(User user, Object authenticationDetails, ActionType actionType, Exception e) {
|
||||
public void logLoginAction(User user, Object authenticationDetails, ActionType actionType, Exception e, String provider) {
|
||||
String clientAddress = "Unknown";
|
||||
String browser = "Unknown";
|
||||
String os = "Unknown";
|
||||
String device = "Unknown";
|
||||
if (authenticationDetails instanceof RestAuthenticationDetails) {
|
||||
RestAuthenticationDetails details = (RestAuthenticationDetails) authenticationDetails;
|
||||
AuthorizationDetails details = RestAuthenticationDetailsUtils.getRestAuthenticationDetails((RestAuthenticationDetails) authenticationDetails);
|
||||
clientAddress = details.getClientAddress();
|
||||
if (details.getUserAgent() != null) {
|
||||
Client userAgent = details.getUserAgent();
|
||||
if (userAgent.userAgent != null) {
|
||||
browser = userAgent.userAgent.family;
|
||||
if (userAgent.userAgent.major != null) {
|
||||
browser += " " + userAgent.userAgent.major;
|
||||
if (userAgent.userAgent.minor != null) {
|
||||
browser += "." + userAgent.userAgent.minor;
|
||||
if (userAgent.userAgent.patch != null) {
|
||||
browser += "." + userAgent.userAgent.patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (userAgent.os != null) {
|
||||
os = userAgent.os.family;
|
||||
if (userAgent.os.major != null) {
|
||||
os += " " + userAgent.os.major;
|
||||
if (userAgent.os.minor != null) {
|
||||
os += "." + userAgent.os.minor;
|
||||
if (userAgent.os.patch != null) {
|
||||
os += "." + userAgent.os.patch;
|
||||
if (userAgent.os.patchMinor != null) {
|
||||
os += "." + userAgent.os.patchMinor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (userAgent.device != null) {
|
||||
device = userAgent.device.family;
|
||||
}
|
||||
}
|
||||
browser = details.getBrowser();
|
||||
os = details.getOs();
|
||||
device = details.getDevice();
|
||||
}
|
||||
if (actionType == ActionType.LOGIN && e == null) {
|
||||
userService.setLastLoginTs(user.getTenantId(), user.getId());
|
||||
}
|
||||
auditLogService.logEntityAction(
|
||||
user.getTenantId(), user.getCustomerId(), user.getId(),
|
||||
user.getName(), user.getId(), null, actionType, e, clientAddress, browser, os, device);
|
||||
user.getName(), user.getId(), null, actionType, e, clientAddress, browser, os, device, provider);
|
||||
}
|
||||
|
||||
private static boolean isPositiveInteger(Integer val) {
|
||||
|
||||
@ -42,6 +42,6 @@ public interface SystemSecurityService {
|
||||
|
||||
String getBaseUrl(TenantId tenantId, CustomerId customerId, HttpServletRequest httpServletRequest);
|
||||
|
||||
void logLoginAction(User user, Object authenticationDetails, ActionType actionType, Exception e);
|
||||
void logLoginAction(User user, Object authenticationDetails, ActionType actionType, Exception e, String provider);
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 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.utils;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class AuthorizationDetails {
|
||||
private String clientAddress;
|
||||
private String browser;
|
||||
private String os;
|
||||
private String device;
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 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.utils;
|
||||
|
||||
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
|
||||
import ua_parser.Client;
|
||||
|
||||
public class RestAuthenticationDetailsUtils {
|
||||
|
||||
public static AuthorizationDetails getRestAuthenticationDetails(RestAuthenticationDetails details) {
|
||||
String clientAddress = details.getClientAddress();
|
||||
String browser = "Unknown";
|
||||
String os = "Unknown";
|
||||
String device = "Unknown";
|
||||
if (details.getUserAgent() != null) {
|
||||
Client userAgent = details.getUserAgent();
|
||||
if (userAgent.userAgent != null) {
|
||||
browser = userAgent.userAgent.family;
|
||||
if (userAgent.userAgent.major != null) {
|
||||
browser += " " + userAgent.userAgent.major;
|
||||
if (userAgent.userAgent.minor != null) {
|
||||
browser += "." + userAgent.userAgent.minor;
|
||||
if (userAgent.userAgent.patch != null) {
|
||||
browser += "." + userAgent.userAgent.patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (userAgent.os != null) {
|
||||
os = userAgent.os.family;
|
||||
if (userAgent.os.major != null) {
|
||||
os += " " + userAgent.os.major;
|
||||
if (userAgent.os.minor != null) {
|
||||
os += "." + userAgent.os.minor;
|
||||
if (userAgent.os.patch != null) {
|
||||
os += "." + userAgent.os.patch;
|
||||
if (userAgent.os.patchMinor != null) {
|
||||
os += "." + userAgent.os.patchMinor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (userAgent.device != null) {
|
||||
device = userAgent.device.family;
|
||||
}
|
||||
}
|
||||
return new AuthorizationDetails(clientAddress, browser, os, device);
|
||||
}
|
||||
}
|
||||
@ -257,10 +257,12 @@ public class AuditLogServiceImpl implements AuditLogService {
|
||||
String browser = extractParameter(String.class, 1, additionalInfo);
|
||||
String os = extractParameter(String.class, 2, additionalInfo);
|
||||
String device = extractParameter(String.class, 3, additionalInfo);
|
||||
String provider = extractParameter(String.class, 4, additionalInfo);
|
||||
actionData.put("clientAddress", clientAddress);
|
||||
actionData.put("browser", browser);
|
||||
actionData.put("os", os);
|
||||
actionData.put("device", device);
|
||||
actionData.put("provider", provider);
|
||||
break;
|
||||
case PROVISION_SUCCESS:
|
||||
case PROVISION_FAILURE:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user