0

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?

Faramarz Afzali
  • 726
  • 1
  • 10
  • 24
Mistborn
  • 11
  • 3

1 Answers1

0

The simplest approach would be a try catch statement since the Stacktrace for the exception is missing in your question I ave to guess that your exception is thrown in line

context = connect(user, password);//where authentication did

A solution would then be

try {
    context = connect(user, password);//where authentication did
} catch (AuthenticationException e) {
    log.error("User could not autheticate");
    someRepository.save(CustomErrorObject);
    someOtherCustomSaveMethod();
    throw e;
}

the error behavior is still the same since the exception is re thrown in the catch statement, but the save code before can be executed.

GJohannes
  • 1,408
  • 1
  • 8
  • 14
  • Wll not exactly, my exception throw in context = connect(user, password); LDAP throw a exception when user and password are incorrect, in catch clausule I need to save information – Mistborn Apr 12 '22 at 22:15
  • Sorry my mistake. Obiously in this line. I have eddited my answer. The Solution should work either way. You just have to surround your correct line with try catch – GJohannes Apr 12 '22 at 22:23
  • Just as you say I have my code, in calusule try my context = connect(user, password); and catch block my service where I try to save registry, but not work nothing NOTHING – Mistborn Apr 12 '22 at 23:11
  • I update my question about what type of exception catch, with your solution don't work. Have you any other way to achive that? – Mistborn Apr 13 '22 at 00:59