Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error handling #43

Merged
merged 2 commits into from
Dec 22, 2024
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
5 changes: 3 additions & 2 deletions server/src/main/java/io/flowinquiry/FlowInquiryApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
Expand All @@ -28,7 +29,6 @@
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.Transactional;
import tech.jhipster.config.DefaultProfileUtil;

@SpringBootApplication
@EnableConfigurationProperties({
Expand Down Expand Up @@ -85,7 +85,8 @@ public static void main(String[] args) {

SpringApplication app = new SpringApplication(FlowInquiryApp.class);

DefaultProfileUtil.addDefaultProfile(app);
app.setDefaultProperties(
Map.of("spring.profiles.default", FlowInquiryProfiles.SPRING_PROFILE_DEVELOPMENT));
Environment env = app.run(args).getEnvironment();
logApplicationStartup(env);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.task.DelegatingSecurityContextTaskExecutor;
import tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor;

@Configuration
@EnableAsync
Expand All @@ -38,7 +37,7 @@ public Executor getAsyncExecutor() {
executor.setMaxPoolSize(taskExecutionProperties.getPool().getMaxSize());
executor.setQueueCapacity(taskExecutionProperties.getPool().getQueueCapacity());
executor.setThreadNamePrefix(taskExecutionProperties.getThreadNamePrefix());
return new ExceptionHandlingAsyncTaskExecutor(executor);
return executor;
}

@Bean(name = "auditLogExecutor")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.flowinquiry.config;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.http.HttpStatus;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
import org.springframework.security.web.AuthenticationEntryPoint;

/** Custom handler for token authentication */
public class CustomBearerTokenAuthenticationEntryPoint implements AuthenticationEntryPoint {

private final BearerTokenAuthenticationEntryPoint delegate =
new BearerTokenAuthenticationEntryPoint();

@Override
public void commence(
HttpServletRequest request,
HttpServletResponse response,
org.springframework.security.core.AuthenticationException authException)
throws IOException {

// Add CORS headers
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.addHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");

// Delegate to the default implementation
delegate.commence(request, response, authException);

// Optional: Add additional details in the response body
if (response.getStatus() == HttpStatus.UNAUTHORIZED.value()) {
response.setContentType("application/json");
response.getWriter()
.write(
"{\"error\": \"Unauthorized\", \"message\": \"Token expired or invalid.\"}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
Expand Down Expand Up @@ -102,7 +101,7 @@ public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Buil
exceptions ->
exceptions
.authenticationEntryPoint(
new BearerTokenAuthenticationEntryPoint())
new CustomBearerTokenAuthenticationEntryPoint())
.accessDeniedHandler(new BearerTokenAccessDeniedHandler()));
return http.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.oauth2.jwt.*;

@Configuration
public class SecurityJwtConfiguration {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ protected void initializeResourceHandler(
}

protected CacheControl getCacheControl() {
return CacheControl.maxAge(getJHipsterHttpCacheProperty(), TimeUnit.DAYS).cachePublic();
return CacheControl.maxAge(getHttpCacheProperty(), TimeUnit.DAYS).cachePublic();
}

private int getJHipsterHttpCacheProperty() {
private int getHttpCacheProperty() {
return flowInquiryProperties.getHttp().getCache().getTimeToLiveInDays();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import io.flowinquiry.modules.usermanagement.service.dto.UserKey;
import io.flowinquiry.modules.usermanagement.service.event.DeleteUserEvent;
import io.flowinquiry.modules.usermanagement.service.mapper.UserMapper;
import io.flowinquiry.platform.utils.Random;
import io.flowinquiry.query.QueryDTO;
import io.flowinquiry.security.Constants;
import io.flowinquiry.security.SecurityUtils;
Expand All @@ -30,7 +31,6 @@
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tech.jhipster.security.RandomUtil;

/** Service class for managing users. */
@Service
Expand Down Expand Up @@ -99,7 +99,7 @@ public Optional<UserDTO> requestPasswordReset(String mail) {
.filter(user -> Objects.equals(user.getStatus(), UserStatus.ACTIVE))
.map(
user -> {
user.setResetKey(RandomUtil.generateResetKey());
user.setResetKey(Random.generateResetKey());
user.setResetDate(Instant.now());
return user;
})
Expand Down Expand Up @@ -130,7 +130,7 @@ public User registerUser(UserDTO userDTO, String password) {
// new user is not active
newUser.setStatus(UserStatus.PENDING);
// new user gets registration key
newUser.setActivationKey(RandomUtil.generateActivationKey());
newUser.setActivationKey(Random.generateActivationKey());
Set<Authority> authorities = new HashSet<>();
authorityRepository.findById(AuthoritiesConstants.USER).ifPresent(authorities::add);
newUser.setAuthorities(authorities);
Expand Down Expand Up @@ -161,9 +161,9 @@ public UserDTO createUser(UserDTO userDTO) {
} else {
user.setLangKey(userDTO.getLangKey());
}
String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword());
String encryptedPassword = passwordEncoder.encode(Random.generatePassword());
user.setPassword(encryptedPassword);
user.setResetKey(RandomUtil.generateResetKey());
user.setResetKey(Random.generateResetKey());
user.setResetDate(Instant.now());
user.setStatus(UserStatus.PENDING);

Expand Down
7 changes: 2 additions & 5 deletions server/src/main/resources/config/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,10 @@ flowinquiry:
base_url: http://127.0.0.1:3000
# CORS is only enabled by default with the "dev" profile
cors:
# Allow Ionic for JHipster by default (* no longer allowed in Spring Boot 2.4+)
allowed-origins: 'http://localhost:8100,https://localhost:8100,http://localhost:9000,https://localhost:9000,http://localhost:9060,https://localhost:9060'
# Enable CORS when running in GitHub Codespaces
allowed-origin-patterns: 'https://*.githubpreview.dev'
allowed-origins: 'http://localhost:3000,http://localhost:8080'
allowed-methods: '*'
allowed-headers: '*'
exposed-headers: 'Authorization,Link,X-Total-Count,X-${jhipster.clientApp.name}-alert,X-${jhipster.clientApp.name}-error,X-${jhipster.clientApp.name}-params'
exposed-headers: 'Authorization,Link,X-Total-Count'
allow-credentials: true
max-age: 1800
security:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import tech.jhipster.config.JHipsterDefaults;

class StaticResourcesWebConfigurerTest {

Expand Down Expand Up @@ -62,9 +61,7 @@ void shouldInitializeResourceHandlerWithCacheControlAndLocations() {

@Test
void shouldCreateCacheControlBasedOnJhipsterDefaultProperties() {
CacheControl cacheExpected =
CacheControl.maxAge(JHipsterDefaults.Http.Cache.timeToLiveInDays, TimeUnit.DAYS)
.cachePublic();
CacheControl cacheExpected = CacheControl.maxAge(1461, TimeUnit.DAYS).cachePublic();
assertThat(staticResourcesWebConfiguration.getCacheControl())
.extracting(CacheControl::getHeaderValue)
.isEqualTo(cacheExpected.getHeaderValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.flowinquiry.modules.usermanagement.service.UserService;
import io.flowinquiry.modules.usermanagement.service.dto.ResourcePermissionDTO;
import io.flowinquiry.modules.usermanagement.service.dto.UserDTO;
import io.flowinquiry.platform.utils.Random;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
Expand All @@ -25,7 +26,6 @@
import org.springframework.data.auditing.DateTimeProvider;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.transaction.annotation.Transactional;
import tech.jhipster.security.RandomUtil;

/** Integration tests for {@link UserService}. */
@IntegrationTest
Expand Down Expand Up @@ -110,7 +110,7 @@ void assertThatOnlyActivatedUserCanRequestPasswordReset() {
@Transactional
void assertThatResetKeyMustNotBeOlderThan24Hours() {
Instant daysAgo = Instant.now().minus(25, ChronoUnit.HOURS);
String resetKey = RandomUtil.generateResetKey();
String resetKey = Random.generateResetKey();
user.setStatus(UserStatus.ACTIVE);
user.setResetDate(daysAgo);
user.setResetKey(resetKey);
Expand Down Expand Up @@ -142,7 +142,7 @@ void assertThatResetKeyMustBeValid() {
void assertThatUserCanResetPassword() {
String oldPassword = user.getPassword();
Instant daysAgo = Instant.now().minus(2, ChronoUnit.HOURS);
String resetKey = RandomUtil.generateResetKey();
String resetKey = Random.generateResetKey();
user.setStatus(UserStatus.ACTIVE);
user.setResetDate(daysAgo);
user.setResetKey(resetKey);
Expand Down
1 change: 1 addition & 0 deletions tools/platform/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ repositories {

dependencies {
implementation(libs.bundles.logback)
implementation("org.apache.commons:commons-lang3:3.17.0")

testImplementation platform(libs.junit.bom)
testImplementation(libs.bundles.junit)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.flowinquiry.platform.utils;

import org.apache.commons.lang3.RandomStringUtils;

import java.security.SecureRandom;

public class Random {
private static final int DEF_COUNT = 20;

private static final SecureRandom SECURE_RANDOM;

static {
SECURE_RANDOM = new SecureRandom();
SECURE_RANDOM.nextBytes(new byte[64]);
}

private Random() {}

/**
* <p>generateRandomAlphanumericString.</p>
*
* @return a {@link java.lang.String} object.
*/
public static String generateRandomAlphanumericString() {
return RandomStringUtils.random(DEF_COUNT, 0, 0, true, true, null, SECURE_RANDOM);
}

/**
* Generate a password.
*
* @return the generated password.
*/
public static String generatePassword() {
return generateRandomAlphanumericString();
}

/**
* Generate an activation key.
*
* @return the generated activation key.
*/
public static String generateActivationKey() {
return generateRandomAlphanumericString();
}

/**
* Generate a reset key.
*
* @return the generated reset key.
*/
public static String generateResetKey() {
return generateRandomAlphanumericString();
}
}
Loading