I've project with spring, spring-boot and JPA. When a user tries to log in I want to register activity in a binnacle. The authentication is with LDAP I have a new class called LoginActivity and implement an interface with only one method to save activity with annotation @Component and my method where a want to save information when user put credentials wrong I have annotation
@Transactional(propagation = Propagation.REQUIRES_NEW) And I have another method where I try to save information in my database I debug my code and it looks good and the process finished well. But when I saw my database I don't see anything I use DTO objects between classes
My method authentication:
@Override
@Transactional
public Authentication authenticate(Authentication authentication) {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
List<GrantedAuthority> authorities = (List<GrantedAuthority>) authentication.getAuthorities();
...
context = connect(user, password);//where authentication did
My DTO class, I use lombok
@Data
@Builder
public class LoginDTO {
private String user;
private String tracking;
private Map<String, Boolean> roles;
private String name;
private String lastName;
private boolean loginSuccess;
private String ipAddress;
}
I set every value in my class DTO
LoginDTO loginDTO = LoginDTO.builder()
.loginSuccess(true)
.tracking(tracking)
.lastName(lastName)
.name(name)
.roles(roles)
.user(user)
.ipAddress(httpServletRequest.getRemoteAddr())
.build();
loginActivity.saveLoginActivity(LoginDTO);
My interface
@FunctionalInterface
public interface LoginActivity {
public void saveLoginActivity(LoginDTO loginDTO);
}
My class than implement interface
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class LoginActivityImpl implements LoginActivity {
My entity
@Entity(name = "activity_desk_control")
@Setter
@Getter
public class ActivityDeskControlEntity {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
@Basic(optional = false)
@Size(max = 255)
@Column(name = "id")
private String id;
@ManyToOne
@JoinColumn(name = "id_user_desk")
private DeskUserLogEntity idUserDesk;
@Column(name = "creation_date")
private Date creationDate;
@Column(name = "id_tracking")
private String idTracking;
@ManyToOne
@JoinColumn(name = "id_service_desk_control")
private ServiceDeskControlEntity idServiceDeskControl;
@Column(name = "params")
@Lob
private String params;
@Column(name = "url")
private String url;
@Column(name = "ip_address")
private String ipAddress;
@Column(name = "login_success")
private int loginSuccess;
@Column(name = "logout")
private int logout;
@Column(name = "logout_date")
private Date logoutDate;
}
My method where I save activity if authentication was well
public void saveMultipart(ActivityDeskControlEntity activityDeskControlEntity) {
this.activityDeskControlRepository.save(activityDeskControlEntity);
}
My method where I save activity if authentication was wrong
@Transactional(propagation = Propagation.REQUIRES_NEW)
public SimpleResponse saveMultipartLoginFail(ActivityDeskControlEntity activityDeskControlEntity) {
this.activityDeskControlRepository.save(activityDeskControlEntity);
}
Have you some idea how I can save information if I got an exception in JPA? I look some links like this but not work. My database is Oracle 19c
Update 1 The exception I get when I put credentials wrong is
javax.naming.AuthenticationException: [LDAP: error code 49 - Invalid Credentials]
In this scenario I want to save information the login fail.
Update 2
In the scenario that throws an exception is
context = connect(user, password);
For default LDAP throw an exception when user and password are wrong in consequence in this exception I want to save.
Update 3
I saw in documentation says:
Any RuntimeException or Error triggers rollback, and any checked Exception does not.
When the user put credentials wrong throw an exception that extends RuntimeException
import org.springframework.security.core.AuthenticationException;
/**
* Thrown if an authentication request is rejected because the credentials are invalid.
* For this exception to be thrown, it means the account is neither locked nor disabled.
*
* @author Ben Alex
*/
public class BadCredentialsException extends AuthenticationException {
// ~ Constructors
// ===================================================================================================
/**
* Constructs a <code>BadCredentialsException</code> with the specified message.
*
* @param msg the detail message
*/
public BadCredentialsException(String msg) {
super(msg);
}
/**
* Constructs a <code>BadCredentialsException</code> with the specified message and
* root cause.
*
* @param msg the detail message
* @param t root cause
*/
public BadCredentialsException(String msg, Throwable t) {
super(msg, t);
}
}
/**
* Abstract superclass for all exceptions related to an {@link Authentication} object
* being invalid for whatever reason.
*
* @author Ben Alex
*/
public abstract class AuthenticationException extends RuntimeException {
// ~ Constructors
// ===================================================================================================
/**
* Constructs an {@code AuthenticationException} with the specified message and root
* cause.
*
* @param msg the detail message
* @param t the root cause
*/
public AuthenticationException(String msg, Throwable t) {
super(msg, t);
}
/**
* Constructs an {@code AuthenticationException} with the specified message and no
* root cause.
*
* @param msg the detailed message
*/
public AuthenticationException(String msg) {
super(msg);
}
}
I tried to change type of exception, but I couldn't, why? spring security to expected BadCredentialsException and not my own BadCredentialsException.
Are there any way to achieve that?