log4j2 monitorInterval using spring cloud config server - log4j2

I'm trying to read the log4j2 configuration from config server during application startup.
bootstrap.yml
spring:
application:
name: loggingApp
cloud:
config:
uri: http://localhost:8888
logging:
config: http://localhost:8888/loggingApp/raw/master/loggingApp-log4j2-DEV.xml
The application seems to get the configuration properly during start up as I see the appropriate log levels. However, the automatic configuration doesn't seem to work. When I change the log level of the loggers, looks like it didn't read the updated config from config server after the monitorInterval has passed. I've set the monitorInterval to 10 seconds. As per the documentation the minimum interval should be 5 seconds. If I point to a file on local drive, instead of the config server url, it is working fine. I tried using -Dlog4j.configurationFile as jvm arg as well as spring configuration logging.config to see if one of those work, but none worked.
https://logging.apache.org/log4j/2.x/manual/configuration.html#AutomaticReconfiguration
https://logging.apache.org/log4j/2.x/log4j-spring-cloud-config/log4j-spring-cloud-config-client/index.html
I'm using spring-boot 2.2.5.RELEASE, log4j2 2.13.1 and spring-cloud Hoxton.SR3 versions.
This is how the git repo looks like where config files are being read from

I too tried the same and it did not work. It seems the <Configuration monitorInternal="10"> property would only have worked if we use log4j.configurationFile property to load the log4j2 config file as mentioned in Apache's Log4j Spring Cloud Configuration Guide .
I used the spring actuator refresh approach to accomplish this task. However this does not reload the configs on its own. So there is work around to meet the required ends. Create a scheduler in your spring application that hits the actuator refresh url on specified intervals as below
#Component
#EnableScheduling
public class RefreshScheduler {
#Autowired
private RestTemplate restTemplate;
#Scheduled(fixedRate = 60000)
private void postRefreshEndPoint() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(headers);
restTemplate.postForEntity("http://localhost:8080/actuator/refresh", entity, String.class);
}
}
This is surely a very dirty way of somehow achieving the required functionality. It works though :)
As a side note : Isn't it better to not have automatic refresh? My argument would be : It's possible developers by mistake ( or just for fun ) do changes to the configs in GIT. And this will lead to a change in the live application in prodcution.
However if we have the actuator refresh URL as mandatory for refreshing the spring context, this can be stopped. Only authorized memebers from the production/operations team would have access to this refresh url and they can decide whether to actually refresh the production spring beans when a commit on GIT has been done.

Related

How can I know if my app is running under Kestrel or HTTP.sys?

What's the best way to know if my app is running under Kestrel or HTTP.sys. All that I have found so far is to check for "Kestrel" in one of the HttpConext property class names.
Within an MVC controller I can do something like this:
Boolean IsKestrel = HttpContext.Features.GetType().ToString().Contains("Kestrel");
i.e. check this:
Features = {Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection<Microsoft.AspNetCore.Hosting.HostingApplication.Context>}
When using HTTP.sys I only get:
Features = {Microsoft.AspNetCore.Http.Features.FeatureCollection}
(Is "Http" here enough to know that this is HTTP.sys?)
There must be a better way. Is there an obvious property somewhere that contains the name of the host being used?
A broader question might be, how do I know what the builder pattern built?
Update
Found something better, but still looking for a Property that has the server name or type.
In an MVC controller:
var isKestrel = HttpContext.Request.Headers.GetType().ToString().Contains(".Kestrel.");
var isHTTPsys = HttpContext.Request.Headers.GetType().ToString().Contains(".HttpSys.");
At the operating system level, netsh http show servicestate will list all active URLs listening via HTTP.SYS.
From code you can locate an instance of Microsoft.AspNetCore.Hosting.Server.IServer and check what its implementation is, in netcore 6:
Kestrel => Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl
IIS ==> Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer
HTTP.SYS => Microsoft.AspNetCore.Server.HttpSys.MessagePump
This relies on implementation details (so can break), also other extensions can change these e.g. CoreWcf creates CoreWCF.Configuration.WrappingIServer that wraps one of the above implementations.
you can use System.Diagnostics.Process.GetCurrentProcess().ProcessName
I am not sure whether you want to check this information using the code only or you are just looking for a way to know on which web server your app is running.
In my search result, I found that we could set the ports for a specific web server. When the application will run on that specific web server then it will use that pre-configured port. I am assuming your app also has a similar configuration. You could set the different ports for Kestrel, Http.sys, or IIS. By checking the port number you could say that on which web server your site is running.
You could try to go to the launchSettings.json file in your project where you could configure ports for IIS and Kestral.
Helpful References:
Kestrel Web Server in ASP.NET Core
Understand HTTP.sys Web Server In ASP.NET Core
Hello this is a good question, you question is asking how to find out from inside the code and not from a console.
OOB I did not find anything. So, I had to get very creative to figure this out, sorry for the typo's its brand new stuff...
Option 1:
Since the Kestrel section & endpoints are inside the appsettings.json I used that to find out if its hosted by Kestrel!
//Please create a static class to hold the config.
public static class MyStartupIsItKestrelConfiguration
{
public static IConfiguration Configuration;
public bool static IsKestrel()
{
//check your section kestrel??
var kestrel = configuration.GetSection("Kestrel");
// now check kestrel section or any other section
// see picture for kestrel endpoint in app setting sbelow
return true;
}
}
Now you can access it anywhere and see if you used Kestrel
//Now add it/save it in your startup and access later
public Startup(IConfiguration configuration)
{
Configuration = configuration;
MyStartupIsItKestrelConfiguration.Configuration = configuration;
}
Once you have this
//you can use it in ** YOUR CONTROLLER
MyStartupIsItKestrelConfiguration.IsKestrel();
Option 2:
Please check this public Microsoft.AspNetCore.Http.Features.IFeatureCollection Features { get; }
You can get the features public TFeature? Get<TFeature> (); as a Key Value Pair - and then check the feature for e.g. KESTREL DOES NOT ALLOW PORT SHARING
they split the features namespace in .net core 6 there are breaking changes
You should use the features collection

Propagate X-B3-TraceId between applications using SNS and SQS

I have 2 spring based applications both of them uses spring-sleuth.
Application-1:
AmazonSNS snsPublisher;
snsPublisher.publish(message)
I would like to add MDC context here somehow, so that application-2 can use the same context. Is there any integration that is provided to achieve this ?
Application-2:
#SqsListener
public void process(String message, #Headers Map<String, MessageAttributeValue> sqsHeaders)
When I receive the MDC context(traceId) set by other application in headers, then I need an integration which can add that same MDC context in application-2 as well. So that, when I look at logs I will have a whole picture of what has happened with that request combining both of these applications.

Swagger Base URL is wrong for my application deployed on AWS

I have a Spring Boot application deployed and configured as AWS Route 53 > AWS Load Balance -> 2 EC2 instances which hosted the Spring Boot application.
The URL for the Swagger is
https://applicationXYZ.company.net/release/swagger-ui.html
I'm able to see the page without any issue. But we can't use the 'Tryout' feature because the Base URL is wrong.
On top of the page I do see information as
[ Base URL: service/release]
I have no idea where 'service' became my base URL. I also hit api-docs and also see 'server' in 'host' field.
Could you please help on this?
Note: I'm using Spring Boot Starter 2.0.8.RELEASE and Swagger 2.9.2 (without any Spring Security)
Thanks,
Did you ever try to make a redirect,
//Do redirection inside controller
#RequestMapping("/swagger")
public String greeting() {
return "redirect:/swagger-ui.html";
}
you can try to add bean too, inside main method,
#Bean
RouterFunction<ServerResponse> routerFunction() {
return route(GET("/swagger"), req ->
ServerResponse.temporaryRedirect(URI.create("swagger-ui.html")).build());
}
refer: How to change Swagger-ui URL prefix?

SpecsFor MVC - Can't get site to build / appear

I am attempting to create some UI tests using SpecsFor MVC, I am coming at this from a new user's point of view in terms of testing so could be easily missing something obvious.
The site I'm testing against already uses it's own test DB so I do not need to create one. when I build and debug normally on this site it also starts up a couple of WCF projects which we use for service layer interactions. Presumably I'll need to start these in the specs config but have not got that far yet.
I've followed the documentation and have created this method:
protected override void AfterConfigurationApplied()
{
var config = new SpecsForMvcConfig();
config.UseIISExpress()
.With(Project.Named("TestSite"))
.UsePort(55555)
.CleanupPublishedFiles()
.UseMSBuildExecutableAt(#"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe");
config.BuildRoutesUsing(MvcApplication.RegisterRoutes);
config.UseBrowser(BrowserDriver.Chrome);
_host = new SpecsForIntegrationHost(config);
_host.Start();
}
The routing of the site is set in the Global.asax hence the setting in the above method.
I also have this very basic test in place to just see if I can get it working:
protected override void When()
{
SUT.NavigateTo<HomeController>(u => u.Index());
SUT.FindLinkTo<HomeController>(u => u.About())
.Click();
}
When I debug the tests it successfully starts Chrome but hangs for ages and eventually fails with this error:
OpenQA.Selenium.WebDriverException: The HTTP request to the remote WebDriver server for URL http://localhost:49924/session/bd15d6a15395b4ca204437c340639501/element timed out after 60 seconds.
I'm not sure where that port number or session etc are coming from.
If I'm running my web project normally (outside of this whole testing project) I see a URL like this:
https://localhost:55555
I would have thought I'd see something similar for these tests cases? It doesn't really matter in any case because they're not working.
Am I missing some element of the config? Do I need to set up the WCF layer to run as well?

Grails Spring Security LDAP plugin with multiple Active Directory servers

I have the Grails Spring Security plugin connecting to one Active Directory server with no problems. However, I need to connect to multiple servers. We have some users on one AD server and other users on a different server, so we need to try looking for users in both locations.
For example, in Java I have this working as below:
<authentication-manager>
<authentication-provider ref="provider1"/>
<authentication-provider ref="provider2"/>
...
</authentication-manager>
<ldap-server id="provider1"
url="ldap://LDAPSERVER1.mycompany.intranet"
manager-dn="OU=std_users,OU=users,DC=mycompany,DC=intranet"
manager-password="blah"/>
<ldap-server id="provider2"
url="ldap://DIFFERENT_LDAPSERVER.mycompany.intranet"
manager-dn="OU=std_users,OU=external_users,DC=mycompany,DC=intranet"
manager-password="blah"/>
In Grails I can configure one AD server but cannot work out how to configure more than one:
// LDAP config
grails.plugin.springsecurity.ldap.context.managerDn = 'CN=blah,OU=std_users,OU=users,DC=mycompany,DC=intranet'
grails.plugin.springsecurity.ldap.context.managerPassword = 'the_password'
grails.plugin.springsecurity.ldap.context.server = 'ldap://theserver.mycompany.intranet'
grails.plugin.springsecurity.ldap.authorities.ignorePartialResultException = true // typically needed for Active Directory
grails.plugin.springsecurity.ldap.search.base = 'OU=std_users,OU=users,DC=mycompany,DC=intranet'
grails.plugin.springsecurity.ldap.search.filter="sAMAccountName={0}" // for Active Directory you need this
grails.plugin.springsecurity.ldap.search.searchSubtree = true
grails.plugin.springsecurity.ldap.auth.hideUserNotFoundExceptions = false
I know that you can create a space-separated list of servers but this won't work for me as it will only try one of the servers once it has a connection, whereas I need it to try looking for users in both.
I think I probably need to get stuck into the resources.groovy file but don't know where to start with this - has anyone configured multiple AD locations?
The only other idea I have is to create a virtual directory which brings together all the users in one directory. Can anyone suggest a good way of doing this? I have been looking at http://myvd.sourceforge.net/usecases.html
Any help would be appreciated. Have been googling all day and I am no closer to a solution.
Andrew's answer pointed me in the right direction and I now have this working.
It was A LOT easier to make this work using ActiveDirectoryLdapAuthenticationProvider. This is done as below:
In resources.groovy:
// Domain 1
ldapAuthProvider1(ActiveDirectoryLdapAuthenticationProvider,
"mydomain.com",
"ldap://mydomain.com/"
)
// Domain 2
ldapAuthProvider2(ActiveDirectoryLdapAuthenticationProvider,
"mydomain2.com",
"ldap://mydomain2.com/"
)
In Config.groovy:
grails.plugin.springsecurity.providerNames = ['ldapAuthProvider1', 'ldapAuthProvider2']
This is all the code you need. You can pretty much remove all other grails.plugin.springsecurity.ldap.* settings in Config.groovy as they don't apply to this AD setup.
For documentation, see:
http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ldap-active-directory
If you aren't using AD and want the 'pure LDAP' version:
In resources.groovy:
// Create another ldap authentication provider
ldapAuthProvider2(org.springframework.security.ldap.authentication.LdapAuthenticationProvider,
ref("ldapAuthenticator2"),
ref("ldapAuthoritiesPopulator") // Use default
) {
// Can set other auth provider settings here
}
ldapAuthenticator2(org.springframework.security.ldap.authentication.BindAuthenticator, ref("contextSource2")) {
userSearch = ref("ldapUserSearch2")
}
// Set up the manager to read LDAP
contextSource2(DefaultSpringSecurityContextSource, grailsApplication.config.grails.plugin.springsecurity.ldap.context.server2) {
userDn = grailsApplication.config.grails.plugin.springsecurity.ldap.context.managerDn2 // Manager DN
password = grailsApplication.config.grails.plugin.springsecurity.ldap.context.managerPassword2
}
// Configuration for searching for user
ldapUserSearch2(FilterBasedLdapUserSearch, grailsApplication.config.grails.plugin.springsecurity.ldap.search.base2, grailsApplication.config.grails.plugin.springsecurity.ldap.search.filter2, ref('contextSource2')) {
}
And then in Config.groovy:
// Config for second LDAP AuthenticationProvider - used in resources.groovy
grails.plugin.springsecurity.ldap.context.managerDn2 = 'CN=MANAGER_USER,OU=Users,DC=mycompany,DC=com'
grails.plugin.springsecurity.ldap.context.managerPassword2 = 'manager_password'
grails.plugin.springsecurity.ldap.context.server2 = "ldap://the-ldap-server.com"
grails.plugin.springsecurity.ldap.search.base2 = 'OU=Users,DC=mycompany,DC=com'
grails.plugin.springsecurity.ldap.search.filter2 = "sAMAccountName={0}" // for Active Directory you need this
// Add the AuthenticationProvider to the list
grails.plugin.springsecurity.providerNames = ['ldapAuthProvider', 'ldapAuthProvider2']
This link was very useful for finding out how to set this up:
https://github.com/grails-plugins/grails-spring-security-ldap/blob/master/SpringSecurityLdapGrailsPlugin.groovy
The basic idea would be to construct a second, custom AuthenticationProvider bean within your application's grails-app/conf/spring/resources.groovy file, perhaps modeling it after ldapAuthProvider in https://github.com/grails-plugins/grails-spring-security-ldap/blob/master/SpringSecurityLdapGrailsPlugin.groovy Then, you could add this custom LDAP authenticator bean to the grails.plugin.springsecurity.providerNames list in Config.groovy (or equivalent)

Resources