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