Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ description = 'Spring User Framework'

ext {
springBootVersion = '3.4.4'
lombokVersion = '1.18.36'
lombokVersion = '1.18.38'
}

java {
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import lombok.Builder;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.core.user.OAuth2User;
import com.digitalsanctuary.spring.user.persistence.model.User;
import lombok.Builder;
import lombok.ToString;

/**
Expand Down Expand Up @@ -41,7 +39,7 @@
* }</pre>
*/
@ToString
public class DSUserDetails implements UserDetails, OAuth2User, OidcUser {
public class DSUserDetails implements UserDetails, OidcUser {

/** The Constant serialVersionUID. */
private static final long serialVersionUID = 5286810064622508389L;
Expand Down Expand Up @@ -86,8 +84,8 @@ public DSUserDetails(User user) {
* Instantiates a new DS user details.
*
* @param user the user
* @param oidcUserInfo containing claims about the user
* @param oidcIdToken containing claims about the user
* @param oidcUserInfo containing claims about the user
* @param oidcIdToken containing claims about the user
* @param grantedAuthorities the granted authorities (optional, default = empty list)
*/
@Builder
Expand All @@ -102,8 +100,8 @@ public DSUserDetails(User user, OidcUserInfo oidcUserInfo, OidcIdToken oidcIdTok
* Instantiates a new DS user details.
*
* @param user the user
* @param oidcUserInfo containing claims about the user
* @param oidcIdToken containing claims about the user
* @param oidcUserInfo containing claims about the user
* @param oidcIdToken containing claims about the user
*/
@Builder
public DSUserDetails(User user, OidcUserInfo oidcUserInfo, OidcIdToken oidcIdToken) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,19 @@ public class LoginSuccessService extends SavedRequestAwareAuthenticationSuccessH
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException,
ServletException {
log.debug("LoginSuccessService.onAuthenticationSuccess()");
log.debug("LoginSuccessService.onAuthenticationSuccess:" + "called with authentiation: {}", authentication);
log.debug("LoginSuccessService.onAuthenticationSuccess:" + "called with request: {}", request);
log.debug("LoginSuccessService.onAuthenticationSuccess:" + "called with authentication: {}", authentication);

// Enhanced logging to check request attributes
log.debug("Request URI: {}", request.getRequestURI());
log.debug("Request URL: {}", request.getRequestURL());
log.debug("Request query string: {}", request.getQueryString());
log.debug("Session ID: {}", request.getSession().getId());

// Log saved request if present
Object savedRequest = request.getSession().getAttribute("SPRING_SECURITY_SAVED_REQUEST");
log.debug("Saved request in session: {}", savedRequest);

log.debug("LoginSuccessService.onAuthenticationSuccess:" + "targetUrl: {}", super.determineTargetUrl(request, response));

User user = null;
Expand All @@ -59,22 +71,53 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
}
}

// Create audit event
AuditEvent loginAuditEvent =
AuditEvent.builder().source(this).user(user).sessionId(request.getSession().getId()).ipAddress(UserUtils.getClientIP(request))
.userAgent(request.getHeader("User-Agent")).action("Login").actionStatus("Success").message("Success").build();

eventPublisher.publishEvent(loginAuditEvent);
// Publish audit event in a try-catch to prevent redirection issues
try {
eventPublisher.publishEvent(loginAuditEvent);
} catch (Exception e) {
log.error("Error publishing login audit event", e);
// Continue with the login flow even if audit logging fails
}

// Get and set the target URL with enhanced logging
String targetUrl = super.determineTargetUrl(request, response);
log.debug("Initial targetUrl from super.determineTargetUrl: {}", targetUrl);

if (StringUtils.isEmptyOrWhitespace(targetUrl) || StringUtils.equals(targetUrl, "/")) {
targetUrl = loginSuccessUri;
log.debug("Using configured loginSuccessUri: {}", loginSuccessUri);
this.setDefaultTargetUrl(targetUrl);

log.debug("LoginSuccessService.onAuthenticationSuccess:" + "set defaultTargetUrl to: {}", this.getDefaultTargetUrl());
log.debug("LoginSuccessService.onAuthenticationSuccess:" + "defaultTargetParam: {}", this.getTargetUrlParameter());
} else {
log.debug("Using existing targetUrl: {}", targetUrl);
}

// Set the alwaysUseDefaultTargetUrl to ensure our target URL is always used
this.setAlwaysUseDefaultTargetUrl(true);
log.debug("AlwaysUseDefaultTargetUrl set to: {}", this.isAlwaysUseDefaultTargetUrl());

// Check if there's a redirect URL in the request parameters (common in OAuth2 flows)
String continueParam = request.getParameter("continue");
if (continueParam != null) {
log.debug("Found 'continue' parameter in request: {}", continueParam);
}

// Extra logging to track redirection
log.debug("LoginSuccessService.onAuthenticationSuccess: Proceeding with redirection to {}", this.getDefaultTargetUrl());

// Log the SavedRequest state
log.debug("SavedRequest state before calling super.onAuthenticationSuccess: {}",
request.getSession().getAttribute("SPRING_SECURITY_SAVED_REQUEST"));

super.onAuthenticationSuccess(request, response, authentication);

// This won't execute if the super method redirects, but might help with debugging
log.debug("After super.onAuthenticationSuccess - if you see this, no redirect happened");
}

}
62 changes: 30 additions & 32 deletions src/test/java/com/digitalsanctuary/spring/user/api/UserApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@
import com.digitalsanctuary.spring.user.api.data.Response;
import com.digitalsanctuary.spring.user.api.helper.AssertionsHelper;
import com.digitalsanctuary.spring.user.api.provider.ApiTestRegistrationArgumentsProvider;
import com.digitalsanctuary.spring.user.api.provider.ApiTestUpdatePasswordArgumentsProvider;
import com.digitalsanctuary.spring.user.api.provider.holder.ApiTestArgumentsHolder;
import com.digitalsanctuary.spring.user.dto.PasswordDto;
import com.digitalsanctuary.spring.user.dto.UserDto;
import com.digitalsanctuary.spring.user.jdbc.Jdbc;
import com.digitalsanctuary.spring.user.persistence.model.User;
Expand Down Expand Up @@ -80,36 +78,36 @@ public void resetPassword() throws Exception {
}

// Tests temporarily disabled until OAuth2 dependency issue is resolved
// /**
// * Tests the update password functionality with valid and invalid password combinations.
// *
// * @param argumentsHolder Contains test data for password updates (valid/invalid scenarios)
// * @throws Exception if any error occurs during test execution
// */
// @ParameterizedTest
// @ArgumentsSource(ApiTestUpdatePasswordArgumentsProvider.class)
// @Order(3)
// public void updatePassword(ApiTestArgumentsHolder argumentsHolder) throws Exception {
// // Register and login test user first
// login(baseTestUser);
//
// PasswordDto passwordDto = argumentsHolder.getPasswordDto();
//
// ResultActions action = perform(MockMvcRequestBuilders.post(URL + "/updatePassword")
// .contentType(MediaType.APPLICATION_FORM_URLENCODED)
// .content(buildUrlEncodedFormEntity(passwordDto)));
//
// if (argumentsHolder.getStatus() == DataStatus.VALID) {
// action.andExpect(status().isOk());
// }
// if (argumentsHolder.getStatus() == DataStatus.INVALID) {
// action.andExpect(status().isBadRequest());
// }
//
// MockHttpServletResponse actual = action.andReturn().getResponse();
// Response expected = argumentsHolder.getResponse();
// AssertionsHelper.compareResponses(actual, expected);
// }
// /**
// * Tests the update password functionality with valid and invalid password combinations.
// *
// * @param argumentsHolder Contains test data for password updates (valid/invalid scenarios)
// * @throws Exception if any error occurs during test execution
// */
// @ParameterizedTest
// @ArgumentsSource(ApiTestUpdatePasswordArgumentsProvider.class)
// @Order(3)
// public void updatePassword(ApiTestArgumentsHolder argumentsHolder) throws Exception {
// // Register and login test user first
// login(baseTestUser);
//
// PasswordDto passwordDto = argumentsHolder.getPasswordDto();
//
// ResultActions action = perform(MockMvcRequestBuilders.post(URL + "/updatePassword")
// .contentType(MediaType.APPLICATION_FORM_URLENCODED)
// .content(buildUrlEncodedFormEntity(passwordDto)));
//
// if (argumentsHolder.getStatus() == DataStatus.VALID) {
// action.andExpect(status().isOk());
// }
// if (argumentsHolder.getStatus() == DataStatus.INVALID) {
// action.andExpect(status().isBadRequest());
// }
//
// MockHttpServletResponse actual = action.andReturn().getResponse();
// Response expected = argumentsHolder.getResponse();
// AssertionsHelper.compareResponses(actual, expected);
// }


protected void login(UserDto userDto) {
Expand Down