Is it possible to use config server to set the default timezone? - spring-boot

I am trying to use config server to set the default timezone for the application.
I have tried putting below value in VM argument and its working. -Duser.timezone=IST
However, when I am adding the property user.timezone to application.properties or bootstrap.properties or config server properties, it's not working.
Other thing I tried was using a #PostConstruct like below:
#PostConstruct
public void init() {
// Setting Spring Boot SetTimeZone
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
But here I am hardcoding the timezone information and I need it to be configurable.
I believe application might need this property in the very beginning of the application startup and thus, properties file settings are not working but I am not sure.
Is there any workaround or solution by which I can use config server to set the Default timezone to spring boot application?

Related

Springboot: Spring JPA - How to get datasource properties from server container

I use WAS Liberty Server container which provides server.xml and server.env file for configuring many things in addition to configuring DataSource properties such as url, username, password etc.
For security reasons, these properties are not known to developers for production Liberty servers. However, developers use same server.xml/server.evn files but with different DataSource properties so they can do their work.
So, I might have two server.env files like:
PRODUCTION server.env: dataSourceUrl="server-A-URL" (this URL is not known to developers)
DEVELOPMENT server.env: dataSourceUrl="server-B-URL" (this URL is known to developers)
, then the dataSourceUrl is used in server.xml files in production and development to set the url accordingly.
So, the structure of server.xml/server.env file is same for developers and production, only the DataSource url, username, password are different. This way developers can work using their own DataSource properties and once ready to deploy they app, it is handed to other team which then just changes the DataSource properties to the production values and deploys the application to production server.
With Springboot JPA, I know we can use application.properties file to set these DataSource values. But, we would like to be able to set these to the values located in server.env file. Basically to have something like this in application.properties file:
spring.datasource.url=dataSourceUrl //dataSourceUrl is set in server.env
, then be able to use this value in Java code using #Value injection like:
public class MyClass {
#Value("${spring.datasource.url}")
String dsUrl;
...
}
I have been reading about externalizing properties but I am not able to figure out how to do this
You can use Liberty's jndiEntry elements to make configured values available in JNDI. You will need the jndi-1.0 feature, after which you can configure,
<jndiEntry jndiName="spring/datasource/url" value="${dataSourceUrl}"/>
and access it in your application as:
String dsUrl = InitialContext.doLookup("spring/datasource/url");
Or, from a web or ejb component as:
#Resource(lookup = "spring/datasource/url")
String dsUrl;

Spring-boot #Value properties not overridden by command line arguments

I have a Maven/SpringBootApplication that takes its properties from a Spring config Server. I need to override the values of these properties using command line arguments. unfortunately, the properties keep the values provided by the config server and are not overridden by the command line arguments.
I have confirmed that the parameters are properly passed to the App as I can see being passed to SpringApplication.run.
I can see in the function ConfigurableApplicationContext of Spring Framework the environment carrying the arguments in environment.propertysources.propertySourceList.SimpleCommandLinePropertySource.source.optionArgs
If I try to set a Spring-defined value (e.g. --logging.level.org.springframework.web=TRACE) it works, meaning Spring logs traces
I read all possible threads on the subject but none seem to apply to my problem.
This is my Spring boot app (args are beeing passed to the SpringApplication)
#SpringBootApplication
#ComponentScan("com.mycompany")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Here is the component and the property
#Component
public class TaskProcessor implements com.mycompnay.fwk.task.engine.TaskProcessor {
private RestTemplate restTemplate = new RestTemplate();
#Value("${mycompany.converter.converter-uri.office}")
private String converterUriOffice;
}
The parameter being passed is received by the app (extracted from debugger):
0:"--debug=true"
1:"--logging.level.org.springframework.web=TRACE"
2:"--mycompany.converter.converter-uri.office=foo"
hash:0
value:char[44]#25
I expect the property converterUriOffice to have the value foo
Instead it gets its value from the config server (http://localhost:3000/convert/office)
Links from Devilluminati did the job. Thanks a lot! To make it as clear as possible, here is what I had to do.
1- My application has a matching YML file served by the config server called application.yml
2- Inside the application.yml, I have two profiles and I only wanted the ability to override the arguments while using the local profile.
So here is what I had to add to application.yml:
spring:
profiles: local
cloud:
config:
override-system-properties: false
Once I did that (and restarted the config server to make sure it pulls the latest YML), I am able to override the value above by passing the following to the command line:
--mycompany.converter.converter-uri.office=foo
found following in the documentation https://cloud.spring.io/spring-cloud-static/Edgware.SR2/single/spring-cloud.html#overriding-bootstrap-properties
Overriding the Values of Remote Properties The property sources that
are added to you application by the bootstrap context are often
"remote" (e.g. from a Config Server), and by default they cannot be
overridden locally, except on the command line. If you want to allow
your applications to override the remote properties with their own
System properties or config files, the remote property source has to
grant it permission by setting spring.cloud.config.allowOverride=true
(it doesn’t work to set this locally). Once that flag is set there are
some finer grained settings to control the location of the remote
properties in relation to System properties and the application’s
local configuration: spring.cloud.config.overrideNone=true to override
with any local property source, and
spring.cloud.config.overrideSystemProperties=false if only System
properties and env vars should override the remote settings, but not
the local config files.
same problem here with the solution https://github.com/spring-cloud/spring-cloud-config/issues/907
The documentation is not very clear cause it says that command line
arguments always take precedence over remote configuration.
The property sources that are added to you application by the
bootstrap context are often "remote" (e.g. from a Config Server), and
by default they cannot be overridden locally, except on the command
line.
To achieve that, you have to activate the
spring.cloud.config.override-system-properties=false configuration
(the documentation only talk about System properties but it seems to
be applicable to command line arguments too).

Session cookie custom path

I have an spring boot application and want to deploy it to wildfly12. What I'm trying to achieve is that to set a custom path for JSESSIONID cookie. But after all, my efforts haven't had any results.
I have tried to use this property in my application.properties file:
server.servlet.session.cookie.path=/
When I run the application with the embedded tomcat, everything works fine; But when I deploy my app to wildfly, regardless of the value of that property, it always sets the cookie path to the "context-path" of the application.
I have also tried to use this property also:
server.servlet.context-path=/
but no success so far!
There is also this tag inside the standalone.xml file:
<session-cookie http-only="true" secure="true"/>
but it seems that it has nothing to do with the cookie path, as it doesn't have any property regarding that.
The configuration you are doing is for the embedded server of spring boot application.
Embedded server settings present in application properties (can be check here the section # EMBEDDED SERVER CONFIGURATION and the namespace server.servlet.session.cookie.*).
To modify cookie related configuration on external servers, you have to create CookieSerializer bean which can be used to customize cookie configuration. e.g.
#Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
return serializer;
}
You can refer spring guide for more information.

Spring boot application properties load process change programatically to improve security

I have spring boot micro-service with database credentials define in the application properties.
spring.datasource.url=<<url>>
spring.datasource.username=<<username>>
spring.datasource.password=<<password>>
We do not use spring data source to create the connection manually. Only Spring create the database connection with JPA.(org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration)
We only provide the application properties, but spring create the connections automatically to use with the database connection pool.
Our requirement to enhance the security without using db properties in clear text. Two possible methods.
Encrypt the database credentials
Use the AWS secret manager. (then get the credential with the application load)
For the option1, jasypt can be used, since we are just providing the properties only and do not want to create the data source manually, how to do to understand by the spring framework is the problem. If better I can get some working sample or methods.
Regarding the option-2,
first we need to define secretName.
use the secertName and get the database credentials from AWS secret manager.
update the application.properties programatically to understand by spring framework. (I need to know this step)
I need to use either option1 and option2. Mentioned the issues with each option.
What you could do is use environment variables for your properties. You can use them like this:
spring.datasource.url=${SECRET_URL}
You could then retrieve these and start your Spring process using a ProcessBuilder. (Or set the variables any other way)
I have found the solution for my problem.
We need to define org.springframework.context.ApplicationListenerin spring.factories file. It should define the required application context listener like below.
org.springframework.context.ApplicationListener=com.sample.PropsLoader
PropsLoader class is like this.
public class PropsLoader implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
#Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
String appEnv = environment.getProperty("application.env");
//set new properties based on the application environment.
// calling other methods and depends on the enviornment and get the required value set
Properties props = new Properties();
props.put("new_property", "value");
environment.getPropertySources().addFirst(new PropertiesPropertySource("props", props));
}
}
spring.factories file should define under the resources package and META-INF
folder.
This will set the application context with new properties before loading any other beans.

Set/override Spring / Spring Boot properties at runtime

At the project with Spring Boot we use application.properties but need to configure some of these properties (like port number of logging level) based on an external configuration. We access the configuration via API so it is known only at runtime.
Is there a way to override or set some Spring properties at runtime (for example using a bean) and if yes how can this be achieved?
You could do this with Spring Cloud Config
Just for the purpose of illustration, here's a relatively quick way to see dynamic property overrides at runtime:
First, for your bean to be able to pick up changed properties, you need to annotate it with
#RefreshScope
Add the spring cloud dependency to your spring boot app, eg for gradle
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.1.RELEASE'
( NB You also need the spring boot actuator dependency.)
With the app running, you can view your current config at eg
http://localhost:8080/env
eg if you have a property 'my.property' in application.properties, you'll see something like:
"applicationConfig: [classpath:/application.properties]": {
"my.property": "value1",
etc
To change the value, POST my.property=value2 to /env as application/x-www-form-urlencoded
eg
curl -X POST http://localhost:8080 -d my.property=value2
GET /env again and you'll see the new value appears under the "manager" section
To apply the changed properties, do an empty POST to /refresh. Now your bean will have the new value.
Could you use system properties to pass in the variable? If you configure the PropertyPlaceholderConfigurer you can set the precedence of system properties vs file properties.
For example, something like:
#Bean public PropertyPlaceholderConfigurer placeHolderConfigurer() {
PropertyPlaceholderConfigurer props = new PropertyPlaceholderConfigurer()
props.setSystemPropertiesMode( PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE )
props.setLocations(new
PathMatchingResourcePatternResolver().getResources("classpath:/**.properties"));
props
}
The above would load your .properties file, but we set the priority to be system variables first, so if you set a system variable that will override the same variable in the config.
Alternatively, looking at the docs, Spring recommends defining a search order in your Environment:
[PropertyPlaceholderConfigurer is still appropriate for use when]
existing configuration makes use of the "systemPropertiesMode" and/or "systemPropertiesModeName" properties. Users are encouraged to
move away from using these settings, and rather configure property
source search order through the container's Environment; however,
exact preservation of functionality may be maintained by continuing to
use PropertyPlaceholderConfigurer.
Hopefully one of the above should sort out what you need?

Resources