Spring Boot Actuators and CORS Configuration test failing because DB Props are not provided - java

My Spring Boot application is configured with a Datasource and I have implemented CORS Configs and HttpSecurity .antMatchers for authorizing request.
The application seemed to have been working fine - i.e building and testing and launching when I put plain text db passwords in the props file.
Ever since I moved the creds into a CREDHUB service - the builds fail locally (I remediated that by adding a test active profile in my gradle file which uses an uncommited props file - which actually has the plain text db user and pwd) which uses on Jenkins because the actuator and CORS tests started failing, as Jenkins is not configured to access CREDHUB.
So, my question is:
With this setup, the test seems to bring up the whole application, thus trying to connect to a running database - whose credentials are unavailable locally.
The test won't start properly because the datasource properties prefixed with db are not provided.
How can I start this test without bringing up the database connection?
app.yml
spring:
datasource:
driver-class-name: org.abc.jdbc.Driver
username: ${db.username}
password: ${db.password}
url: jdbc:abc://${db.host}:${db.port}/${db.schema}
ActuatorSecurityTest.Java
#ExtendWith(SpringExtension.class)
#SpringBootTest(webEnvironment = RANDOM_PORT)
#Import(ExceptionHandlerConfiguration.class)
#AutoConfigureWebTestClient(timeout = "30000")
class ActuatorsSecurityTest {
#Autowired
private WebTestClient webClient;
/***********************************************************************************************
* ENDPOINTS: Actuator
***********************************************************************************************/
#Test
void should_allowActuatorInfoEndpoint_withoutAuthentication() {
webClient.get().uri("/actuator/info").exchange().expectStatus().is2xxSuccessful();
}
#Test
void should_notAllowSensitiveActuatorEndpoints_withInValidAuthentication() {
webClient.get().uri("/actuator/env").header("Authorization", "Basic xxx").exchange().expectStatus().is4xxClientError();
}
}

So, I added testImplementation 'com.h2database:h2' and everything came to order.
I was getting datasource dependency issue before.

Related

Spring boot application /actuator/refresh return 404

Facts:
SpringBoot version: 2.5.6
actuator dependency added to pom.xml
in application.yaml the endpoints are enabled:
management:
endpoints:
web:
exposure:
include: '*'
If I make a curl -X POST localhost:8080/actuator/refresh getting the following response:
> "timestamp":"2022-01-20T13:32:48.516+00:00","status":404,"error":"Not
> Found","path":"/actuator/refresh"}
I have checked all posts about this topic and tried out all possible solutions but untill now no success. Where do I fail?
PS: curl localhost:8080/actuator/health is returning a valid response.
{"status":"UP"}
EDIT:
I found out that /actuator/refresh is working with the following spring boot version and below
With newer version until now no success
<version>2.3.12.RELEASE</version>
EDIT 2:
spring boot over 2.4.0 has no refresh endpoint
EDIT 3:
with following deps is
spring-cloud-starter-kubernetes-fabric8-config and Spring Cloud Starter Config allows all entpoints
EDIT 4:
actuator is a spring cloud properties so, it should be available its dependency
The documentation says that all endpoints are available by default except shutdown
By default, all endpoints except for shutdown are enabled. To
configure the enablement of an endpoint, use its
management.endpoint..enabled property. The following example
enables the shutdown endpoint:
https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.enabling
The refresh endpoint is not mentioned into the list of endpoints https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.exposing
If you want to have new custom endpoint, spring actuator provide a way to do it:
#Component
#Endpoint(id="custom-endpoint")
public class CustomEndPoint {
#ReadOperation
public CustomData customEndpoint() {
// you have to define this class CustomData
CustomData data = new CustomData();
// ... set some attributes
return data;
}
}

Spring Boot WebMvcTest returns 302 instead of 401 for GET methods

I have an application with REST endpoints that are secured with JWT authentication (external resource server). After upgrading my project from spring-boot 2.2.7 to 2.4.3 some of the WebMvcTest integration tests are failing. Specifically, test cases for GET requests without JWT tokens - previously they would return 401 UNAUTHORIZED, now they return 302 REDIRECT to http://localhost/oauth2/authorization/keycloak.
#Test
void shouldNotAllowAccessForUnauthenticatedUsers() throws Exception {
// given
var params = createParams();
// when / then
mockMvc.perform(get(MY_URI)
.params(params)
.contentType(MediaType.APPLICATION_JSON)
.content(new byte[0]))
.andExpect(status().isUnauthorized());
}
No custom web security configuration is imported, just #WebMvcTest, #AutoConfigureMockMvc plus #ContextConfiguration for relevant controller and mapper beans.
POST methods in tests without authentication return 403 (as before the upgrade). This problem occurs only in tests - when application is running, calling any endpoint without the token results in 401.
Is there a way to configure WebMvcTest to return 401 instead of 302?
Andy Wilkinson's question inspired me to look deeper into this, since no Keycloak adapter is really added as an explicit dependency (only spring-boot-starter-security, spring-boot-starter-oauth2-client, spring-boot-starter-oauth2-resource-server), but keycloak is mentioned in the config here:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ...
client:
registration:
keycloak:
client-id: ...
client-secret: ...
authorization-grant-type: ...
scope: ...
provider:
keycloak:
authorization-uri: ...
token-uri: ...
Requests for app's endpoints are authenticated with JWT tokens from the issuer-uri, but HTTP client calls to other services are authenticated using client registration in Keycloak (for service-to-service authentication).
Anyway, I believe this change of behavior after upgrade is due to a feature introduced in Spring Boot 2.3, specifically: "OAuth2 parameter binding in #WebMvcTest". Auto-configuration for OAuth2 is now included in #WebMvcTest which resulted in this test trying to redirect to keycloak using the client configuration (which in runtime is used only for service-to-service).
I fixed the issue by annotating the test class with:
#ImportAutoConfiguration(exclude = {OAuth2ClientAutoConfiguration.class, OAuth2ResourceServerAutoConfiguration.class})
(Resource server config had to be excluded as well to handle mocked JWT properly.)
Maybe someone will find this helpful.

Launching two spring boot apps in integration test

I have a spring boot integration test. Currently it is running on the test through my test server app(MockServerApp.java) which is located in src/test/resources.
I want to also launch my spring boot app (App.java) before the integration tests are launched so it could connect and exercise soap calls that I will be adding to the integration test rather than manually running the main app server and then launching my integration test
My MockServerApp is configured to port 9119.
My App(main app) is configured to port 28433.
They are both running on localhost.
At first I tried running the two apps at the same time using SpringBootTest
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,classes = {App.class,MockServerApp.class
})
public class BillingMediatorIT {
#Test
public void testOne(){
}
}
But this only launches the mock server on port 9119.
I then tried launching it before integration tests like this
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,classes = {App.class,MockServerApp.class
})
public class BillingMediatorIT {
static ConfigurableApplicationContext context;
#BeforeClass
static public void setup(){
SpringApplication springApplication = new SpringApplicationBuilder()
.sources(App.class)
.build();
context = springApplication.run();
}
#Test
public void testOne(){
}
}
This gave me an error though saying that the address is already in use.
my test.properties
server.ssl.enabled=false
logging.config=classpath:logback-spring.xml
logging.file=messages
logging.file.max-size=50MB
logging.level.com.nulogix=DEBUG
billing.engine.address=127.0.0.1
billing.engine.port=9119
billing.engine.api.version=0.97
billing.engine.core.version=0.97
billing.engine.core.name=Patient_Responsibility
my app.properties
server.port=28433
server.ssl.enabled=true
server.ssl.key-store=/Users/asluborski/Documents/mock.jks
server.ssl.key-store-password=Nul0gix
logging.config=classpath:logback-spring.xml
logging.file=messages
logging.file.max-size=50MB
logging.level.com.nulogix=DEBUG
billing.engine.address=127.0.0.1
billing.engine.port=9119
billing.engine.api.version=0.97
billing.engine.core.version=0.97
billing.engine.core.name=Patient_Responsibility
So after playing around and changing the server.ports in both properties files, I've realized that the integration test is still running with my MockServerApp although my spring boot test is directing towards the main app class. I've tried using property source but it didn't work.
Something I should add is that both my properties in src/test/resources and src/main/resources are both named application.properties. I am not sure if this could be causing the conflict but I simply copied over the properties from main and then just changed the server.port inside the file. I am not sure how to change the name of the .properties.
Here are two suggestions that may help depending on your situation:
If all you need is a controller to communicate with, then just set up one in your test directory (i.e. same locations as your other tests) and write your tests talk to that controller. Your use of SpringRunner/SpringBootTest will turn on this controller as though it was part of your main application for the purposes of your tests. Just note that it will run on the same port as your main application, so just make sure it has different endpoints to avoid any collision.
If your Mocked Server is more complicated, configuration of your endpoints is an issue, or you feel like you may be adding multiple connections to services (think nginx server, database, messaging etc) to these test in the future, then I would suggest looking at Testcontainers. This allows you to use images in docker containers that you can connect to as resources in your integration tests.

How to do we know , if spring boot application is using connection pool

I have one spring boot application and am using managed
postgres as backend. I do not have any admin permissions on postgres.
If i do not mention anything in my spring boot application, does that mean is it using some connection pooling?
my spring boot application.yml is like below
spring:
profiles: prod
datasource:
driver-class-name: org.postgresql.Driver
url: <<jdbc-url>>
username: prddb
password:
tomcat:
validation-interval: 30000
test-on-borrow: true
validation-query: SELECT 1
when check i dashboard, my apps almost using all connections .
If you added the dependency in pom.xml, spring boot should scan and create a connection pool, else you can specify the datasource manually in the .properties file like so:
spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
Also to test the connection Pool, you can create a simple test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class ConnectionPoolTest {
#Autowired
private DataSource dataSource;
#Test
public void connectionPoolTest() {
assertThat(dataSource.getClass().getName())
.isEqualTo("org.apache.tomcat.jdbc.pool.DataSource");
}
}

Dynamically change security.oauth2.resource.user-info-uri in Spring OAuth2 #EnableResourceServer

I have a Spring Boot app as follows:
#SpringBootApplication
#EnableResourceServer
#EnableDiscoveryClient
public class App
{
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
And i have configured oauth2 properties in application.properties.
security.oauth2.resource.user-info-uri=http://localhost:9000/user
However, I need to change this URI depending on the request I send to my Spring Boot App.
For example:
If I receive a request to my Spring Boot App to URL htpp://test.localhost:8000 I would want the user-info-url to be http://test.localhost:9000/user.
But if I receive a request to http://localhost:8000 I want the user-info-url to be http://localhost:9000/user.
My intention is to manage different environments depending on the subdomain.
Is there a way to dynamically change this URI in code instead of hardcoding it as a property?
Spring Cloud Config
By leveraging a Spring Cloud Config server, you can externalize your configuration and push updates to application properties. A simple implementation is backed by a Git repository where you'll store your application.properties file. You commit your changes and then make a POST request the /refresh endpoint that will trigger a reload of your configuration.
There are more advanced scenarios as well but hopefully that's enough to get you started.
Here's a simple Getting Started guide.

Categories