Skip to content

Commit

Permalink
Adding Springs AuditorAware capabilities (#368)
Browse files Browse the repository at this point in the history
  • Loading branch information
agordon-vivid authored Dec 13, 2024
1 parent 6d0090c commit dd77c7c
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package ca.bc.gov.nrs.wfprev;

import org.springframework.data.domain.AuditorAware;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Component
public class SpringSecurityAuditorAware implements AuditorAware<String> {

@Override
public Optional<String> getCurrentAuditor() {
return Optional.ofNullable(SecurityContextHolder.getContext())
.map(context -> context.getAuthentication())
.filter(Authentication::isAuthenticated)
.map(authentication -> {
Object principal = authentication.getPrincipal();
if (principal instanceof DefaultOAuth2AuthenticatedPrincipal) {
// Extract username or preferred identifier
DefaultOAuth2AuthenticatedPrincipal oauthPrincipal = (DefaultOAuth2AuthenticatedPrincipal) principal;
return (String) oauthPrincipal.getAttribute("preferred_username"); // Adjust key to match your provider
}
throw new IllegalStateException("Principal is not of type DefaultOAuth2AuthenticatedPrincipal");
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.web.filter.ForwardedHeaderFilter;

import com.fasterxml.jackson.annotation.JsonFormat;
Expand All @@ -19,6 +20,7 @@
import jakarta.servlet.DispatcherType;

@SpringBootApplication
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
public class WfprevApiApplication {
/*
* Run the application as a JAR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
Expand All @@ -24,13 +25,14 @@
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.UUID;

@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(name = "project")
@JsonIgnoreProperties(ignoreUnknown = false)
@Data
Expand All @@ -39,6 +41,7 @@
@AllArgsConstructor
@NoArgsConstructor
public class ProjectEntity implements Serializable {

@Id
@UuidGenerator
@GeneratedValue(strategy = GenerationType.UUID)
Expand All @@ -49,7 +52,7 @@ public class ProjectEntity implements Serializable {
@JoinColumn(name = "project_type_code")
private ProjectTypeCodeEntity projectTypeCode;

@Column(name = "project_number", columnDefinition="Decimal(10)", insertable = false, updatable = true)
@Column(name = "project_number", columnDefinition = "Decimal(10)", insertable = false, updatable = true)
private Integer projectNumber;

@NotNull
Expand Down Expand Up @@ -81,7 +84,7 @@ public class ProjectEntity implements Serializable {
@Column(name = "bc_parks_region_org_unit_id", columnDefinition = "Decimal(10)")
private Integer bcParksRegionOrgUnitId;

@Column(name = "bcParksSectionOrgUnitId", columnDefinition = "Decimal(10)")
@Column(name = "bc_parks_section_org_unit_id", columnDefinition = "Decimal(10)")
private Integer bcParksSectionOrgUnitId;

@NotNull
Expand Down Expand Up @@ -144,7 +147,7 @@ public class ProjectEntity implements Serializable {
private Integer revisionCount;

@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name="project_status_code")
@JoinColumn(name = "project_status_code")
private ProjectStatusCodeEntity projectStatusCode;

@CreatedBy
Expand All @@ -166,4 +169,4 @@ public class ProjectEntity implements Serializable {
@NotNull
@Column(name = "update_date")
private Date updateDate;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,9 @@ public ProjectModel createOrUpdateProject(ProjectModel resource) throws ServiceE
try {
if (resource.getProjectGuid() == null) {
resource.setCreateDate(new Date());
//TODO - Fix to use proper user
resource.setCreateUser("SYSTEM");
resource.setProjectGuid(UUID.randomUUID().toString());
resource.setCreateDate(new Date());
resource.setCreateUser("SYSTEM");
resource.setRevisionCount(0); // Initialize revision count for new records
}
// Set audit fields
resource.setUpdateDate(new Date());
//TODO - Fix to use proper user
resource.setUpdateUser("SYSTEM");

ProjectEntity entity = projectResourceAssembler.toEntity(resource);

// Load ForestAreaCode with null checks
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
package ca.bc.gov.nrs.wfprev;

import ca.bc.gov.nrs.wfprev.common.controllers.CheckTokenController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.testcontainers.utility.TestcontainersConfiguration;

import ca.bc.gov.nrs.wfprev.common.controllers.CheckTokenController;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(CheckTokenController.class)
@Import({SecurityConfig.class, TestcontainersConfiguration.class})
@MockBean(JpaMetamodelMappingContext.class)
class CheckTokenControllerTest {

@Autowired
private MockMvc mockMvc;

@MockBean(name = "springSecurityAuditorAware") // Changed to match the expected bean name
private AuditorAware<String> auditorAware;

@Test
@WithMockUser
void testToken_MissingAuthorizationHeader() throws Exception {
mockMvc.perform(get("/check/checkToken")
.contentType(MediaType.APPLICATION_JSON))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isUnauthorized());
}

@Test
@WithMockUser
void testToken_NullTokenInHeader() throws Exception {
mockMvc.perform(get("/check/checkToken")
.header("Authorization", "Bearer ")
.contentType(MediaType.APPLICATION_JSON))
.header("Authorization", "Bearer ")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isUnauthorized());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
import org.springframework.data.jpa.util.JpaMetamodel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
Expand All @@ -29,6 +32,7 @@

@WebMvcTest(CodesController.class)
@Import({SecurityConfig.class, TestcontainersConfiguration.class})
@MockBean(JpaMetamodelMappingContext.class)
class CodesControllerTest {

@MockBean
Expand All @@ -37,6 +41,9 @@ class CodesControllerTest {
@Autowired
private MockMvc mockMvc;

@MockBean(name = "springSecurityAuditorAware") // Changed to match the expected bean name
private AuditorAware<String> auditorAware;

@Test
@WithMockUser
void testGetAllCodes() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
import org.springframework.hateoas.CollectionModel;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
Expand All @@ -40,13 +42,17 @@

@WebMvcTest(ProgramAreaController.class)
@Import({TestSpringSecurity.class, TestcontainersConfiguration.class})
@MockBean(JpaMetamodelMappingContext.class)
class ProgramAreaControllerTest {
@MockBean
private ProgramAreaService programAreaService;

@Autowired
private MockMvc mockMvc;

@MockBean(name = "springSecurityAuditorAware") // Changed to match the expected bean name
private AuditorAware<String> auditorAware;

private Gson gson;

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
import org.springframework.hateoas.CollectionModel;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
Expand Down Expand Up @@ -51,13 +53,17 @@

@WebMvcTest(ProjectBoundaryController.class)
@Import({TestSpringSecurity.class, TestcontainersConfiguration.class, MockMvcRestExceptionConfiguration.class})
@MockBean(JpaMetamodelMappingContext.class)
class ProjectBoundaryControllerTest {
@MockBean
private ProjectBoundaryService projectBoundaryService;

@Autowired
private MockMvc mockMvc;

@MockBean(name = "springSecurityAuditorAware") // Changed to match the expected bean name
private AuditorAware<String> auditorAware;

private Gson gson;

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
import org.springframework.hateoas.CollectionModel;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
Expand All @@ -42,13 +44,17 @@

@WebMvcTest(ProjectController.class)
@Import({TestSpringSecurity.class, TestcontainersConfiguration.class})
@MockBean(JpaMetamodelMappingContext.class)
class ProjectControllerTest {
@MockBean
private ProjectService projectService;

@Autowired
private MockMvc mockMvc;

@MockBean(name = "springSecurityAuditorAware") // Changed to match the expected bean name
private AuditorAware<String> auditorAware;

private Gson gson;

@BeforeEach
Expand Down
Loading

0 comments on commit dd77c7c

Please sign in to comment.