Spring Boot replicate embedded servlet customizer to management port - java

I have a custom WebServerFactoryCustomizer but its not available for management port. What's the best way to make the customization available to server on management port? The regular server is on port =8080 and management server is on port = 8082.
I tried playing around with ServletManagementWebServerFactoryCustomizer but it didn't work. Any pointers will be appreciated.
here is the customizer (to disable TRACE for Undertow)
public class UndertowCustomizer implements
WebServerFactoryCustomizer<ConfigurableUndertowWebServerFactory> {
#Override
public void customize(final ConfigurableUndertowWebServerFactory undertowWebServerFactory) {
undertowWebServerFactory.addDeploymentInfoCustomizers(deploymentInfo ->
deploymentInfo.addInitialHandlerChainWrapper(handler ->
new DisallowedMethodsHandler(handler, HttpString.tryFromString(HttpMethod.TRACE.name())))
);
}
}
A sample reproducible service is at https://github.com/ranarula/WebServerCustomizer

Indeed I feel lack of information regarding this topic as well but I was able to get it working by following the documentation Adding custom endpoints
what you can do is just put the customizer in spring.factories
org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=UndertowCustomizer
javadocs of this class might be helpful as well ManagementContextConfiguration

Related

Keycloak annotation based Resource configuration

I'm recently working with microservices, developed as Spring Boot applications (v 2.2) and in my company we're using Keycloak as authorization server.
We chose it because we need complex policies, roles and groups, and we also need the User Managed Authorization (UMA) to share resources between users.
We configured Keycloak with a single realm and many clients (one client per microservice).
Now, I understand that I need to explicitly define Resources within Keycloak and this is fine, but the question is: do I really need to duplicate all of them in my microservice's property file?
All the documentation, examples and tutorials end up with the same thing, that is something like:
keycloak.policy-enforcer-config.enforcement-mode=PERMISSIVE
keycloak.policy-enforcer-config.paths[0].name=Car Resource
keycloak.policy-enforcer-config.paths[0].path=/cars/create
keycloak.policy-enforcer-config.paths[0].scopes[0]=car:create
keycloak.policy-enforcer-config.paths[1].path=/cars/{id}
keycloak.policy-enforcer-config.paths[1].methods[0].method=GET
keycloak.policy-enforcer-config.paths[1].methods[0].scopes[0]=car:view-detail
keycloak.policy-enforcer-config.paths[1].methods[1].method=DELETE
keycloak.policy-enforcer-config.paths[1].methods[1].scopes[0]=car:delete
(this second example fits better our case because it also uses different authorization scopes per http method).
In real life each microservice we're developing has dozens of endpoints and define them one by one seems to me a waste of time and a weakness in the code's robustness: we change an endpoint, we need to reconfigure it in both Keycloak and the application properties.
Is there a way to use some kind of annotation at Controller level? Something like the following pseudo-code:
#RestController
#RequestMapping("/foo")
public class MyController {
#GetMapping
#KeycloakPolicy(scope = "foo:view")
public ResponseEntity<String> foo() {
...
}
#PostMapping
#KeycloakPolicy(scope = "bar:create")
public ResponseEntity<String> bar() {
...
}
}
In the end, I developed my own project that provides auto-configuration capabilities to a spring-boot project that needs to work as a resource server.
The project is released under MIT2 license and it's available on my github:
keycloak-resource-autoconf

JAX-RS: Server-side user interface

I have a JAX-RS REST service which needs to provide some visual server side output when a REST endpoint is invoked. Later on, I might also want to provide a user interface which an administrator will use for interacting with the web service. I could obviously build REST endpoints for this interaction, and have the administrator invoke these (from a different machine or the same machine) using a provided client application with a UI, but I would like to avoid exposing this functionality to the network. In order to make deployment easy, I would also like everything (i.e. the web service and its administrator UI) to be part of the same application.
I have found that my JAX-RS application will throw a HeadlessException if I try to construct a JFrame or any other top level UI element as described here. I have also found that I can avoid this by setting the system property -Djava.awt.headless=false.
I think I may be able to achieve what I need by setting the headless system property as above and defining a singleton startup EJB that will handle all server side UI tasks:
#Singleton
#Startup
public class UiBean {
private JFrame frame;
#PostConstruct
public void init() {
SwingUtilities.invokeLater(() -> {
frame = new JFrame();
// ...setup UI...
});
}
// JAX-RS resources will inject the UiBean and invoke methods as this one when UI updates are needed.
public void updateSomeUiComponent() {
SwingUtilities.invokeLater(() -> { ... });
}
}
I realise that this design is not ideal. Are there other ways of achieving my requirements? The software being built is a prototype and time is of the essence, so I would like to avoid having to learn complete new technologies (already invested a lot in learning JAX-RS and JPA). Quick-and-dirty is ok, I guess I'm just looking for the least dirty solution ;).
Thanks in advance!

How can I close a SpringBoot WebSocket server?

I imagine it's incredibly simple but I've been unsuccessful in my googling of how-to's, reading of documentation, and perusing of Spring classes.
Spring's doc on their websocket api has been useful and I can see that the project I'm familiarizing myself with uses what it describes to start a server:
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Autowired
private MyWebSocketHandler webSocketHandler;
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler, "/");
}
}
So it's easy enough to start, but I have no idea how to make it stop or pause. I'd like to add a feature to the application that takes down the server (and re-establishes it later) with a click of a button. But I have no ideas about how to stop or pause the server and the documentation doesn't seem to offer anything.
the initialization/management/shutdown of websocket/http connections are handled by spring and tomcat (default). I don't think it's a good idea to deal with it on your own.
a solution would be to decouple (with two springboot apps) the websocket service (which can be started/stopped manually) from the one (which is always up and running) with the "click of a button" page.

Sample SAML Java Config. Project, Broken From the Start

I pulled in the example Java configuration project for Spring's SAML extension. No commits seem to have been made to the project for about six months as of my writing this question. I have not done anything to this project except for run maven package against it.
I then run the application in Spring Tool Suite as a Spring Boot Application and the application runs; however, the application does not run without error and the application endpoint is inaccessible (resulting in am error message): "ERROR: Something went wrong in the authentication process".
I haven't registered any certificates, etc (and may very well need to). There are no instructions provided with the GitHub project for starting or working with the application. I have intentionally not posted the guts of the project as I have left it unmodified.
INFORMATION ON THE ERROR
From Chrome Dev. Tools, I can see a 500 Internal Server Error returned from the request to the localhost:8080 application. So, the issue is definitely with the sample application (or something that I have not done).
The following error is logged to the console on application deployment (I've included both an image and the text as the text is proving difficult to format):
Text:
[2015-08-20 14:41:40.551] boot - 9908 INFO [localhost-startStop-1]
--- HttpMethodDirector: I/O exception (javax.net.ssl.SSLPeerUnverifiedException) caught when processing
request: SSL peer failed hostname validation for name: 46.4.112.4
[2015-08-20 14:41:40.551] boot - 9908 INFO [localhost-startStop-1]
--- HttpMethodDirector: Retrying request
[2015-08-20 14:41:40.795] boot - 9908 ERROR [localhost-startStop-1] --- HTTPMetadataProvider:
Error retrieving metadata from https://idp.ssocircle.com/idp-meta.xml
javax.net.ssl.SSLPeerUnverifiedException: SSL peer failed hostname
validation for name: 46.4.112.4
at org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory.verifyHostname(TLSProtocolSocketFactory.java:233)
at
org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory.createSocket(TLSProtocolSocketFactory.java:194)
I have visited the url endpoint provided by ssocircle and the metadata is exposed.
If I visit the /saml/metadata endpoint of the service provider and get some helpful information: an org.opensaml.saml2.metadata.provider.MetadataProviderException exception. The description if which is "No IDP was configured, please update included metadata with at least one IDP"; however, the source of this may be the above described error.
QUESTION
Am I missing something that is readily apparent to start the example application? In other words, what does this error tell me that I need to be investigating? Or, as it is "non-breaking", do I ignore it?
WHY I'M ASKING
The documentation surrounding the deployment of the Sample Java Configuration application is minimal (as in "non-existant"). The self-documentation only provides "hints", such as the following:
// IDP Metadata configuration - paths to metadata of IDPs in circle of trust is here
// Do no forget to call initialize method on providers
#Bean
#Qualifier("metadata")
public CachingMetadataManager metadata() throws MetadataProviderException {
List<MetadataProvider> providers = new ArrayList<MetadataProvider>();
providers.add(ssoCircleExtendedMetadataProvider());
return new CachingMetadataManager(providers);
}
I am certain there is something I am not doing, particularly since I have not done anything in the deployment of the application except for the run of the mvn package, described above.
The problem occurs due to the sample application's utilization of a deprecated constructor - a deprecation whose warning was explicitly suppressed - for the HTTPMetadataProvider (a fix I will commit, shortly). In configuring the ExtendedMetadataDelegate, the two-parametered constructor is utilized:
#Bean
#Qualifier("idp-ssocircle")
public ExtendedMetadataDelegate ssoCircleExtendedMetadataProvider() throws MetadataProviderException {
#SuppressWarnings({ "deprecation"})
HTTPMetadataProvider httpMetadataProvider = new HTTPMetadataProvider("https://idp.ssocircle.com/idp-meta.xml", 5000);
// other config.s...
}
If replaced with the non-deprecated constructor that takes a java.util.Timer and an org.apache.commons.httpclient.HttpClient (in addition to the metadata url), the sample application works, beautifully, and no errors are logged.
Additional Non-OP-related Information
I had to do the below to get the Sample SAML app to run
After removing the deprecated constructor, I recommend doing two things:
Follow the steps outlined in 4.2.6 of the documentation, i.e. treat the application during setup as the XML-configured application. All the steps need to be taken to "register" the metada.The application will be unable to register its metadata with the current Java configuration (see below; point no. 2)
Change the default configurations in class WebSecurityConfig (read detail, below)
Configuration Change
In the configuration of the ExtendedMetadataDelegate bean ssoCircleExtendedMetadataProvider, change the ExtendedMetadataDelegate's property values as follows:
// code....
extendedMetadataDelegate.setMetadataTrustCheck(true);
extendedMetadataDelegate.setMetadataRequireSignature(false);
// code....
In the ExtendedMetadata bean (different from above), change the property values as below:
// code....
extendedMetadata.setIdpDiscoveryEnabled(true);
extendedMetadata.setSignMetadata(false);
// code....
"Disclaimer"
Whether or not this should be used in production, I do not know; however, it seems to better reflect both the XML-based configuration and resulting metadata of the XML-configured Service Provider example referenced in the SAML Spring Documentation
Just some hints:
I met this exception when I was trying to set up the HTTP-Artifact profile.
There is a hostnameVerifier in org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory (openws-1.5.1) and a verifyHostname() processing before OpenSAML tries to create socket to connect to other host.
I configured sslHostnameVerification to "allowAll" in org.springframework.security.saml.metadata.ExtendedMetadata, the allowed values are "default", "defaultAndLocalhost", "strict", and "allowAll".
It seems in your case, this exception was thrown when the SP (your saml sample) was trying to download the metadata.xml from IdP (ssocircle). The best way to figure out what is happening is to debug when and where the hostnameVerifier was set.
Or you can try set sslHostnameVerification to "allowAll" in the SSOCircle's ExtendedMetadataDelegate's ExtendedMetadata to have a try first..
checkout this answer: It basically describes a plugin I recently released that allows you to configure Spring Boot and Spring Security SAML this way:
#SpringBootApplication
#EnableSAMLSSO
public class SpringBootSecuritySAMLDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootSecuritySAMLDemoApplication.class, args);
}
#Configuration
public static class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
}
#Configuration
public static class MyServiceProviderConfig extends ServiceProviderConfigurerAdapter {
#Override
public void configure(ServiceProviderSecurityBuilder serviceProvider) throws Exception {
serviceProvider
.metadataGenerator()
.entityId("localhost-demo")
.and()
.sso()
.defaultSuccessURL("/home")
.idpSelectionPageURL("/idpselection")
.and()
.logout()
.defaultTargetURL("/")
.and()
.metadataManager()
.metadataLocations("classpath:/idp-ssocircle.xml")
.refreshCheckInterval(0)
.and()
.extendedMetadata()
.idpDiscoveryEnabled(true)
.and()
.keyManager()
.privateKeyDERLocation("classpath:/localhost.key.der")
.publicKeyPEMLocation("classpath:/localhost.cert");
}
}
}
There are a couple Demo apps integrated with SSO Circle

How to develop a web application with a bunch of feature modules

I am developing a web application using spring framework and google app engine. I am wondering if there is a design pattern or framework with the help of which I can develop features of my application as pluggable modules. For example I have identified 4 features of the application:
Oauth Login
User Profile Management
User Group creation
User File management
Now what I need is to develop all these features as independent modules, so that i can detach any of them dynamically and they are as loosely coupled as possible. They can have their own database implementation, their own set of technologies etc. Is there a design principle to implement modules in such a way.
You can take a look at MQ systems (such as RabbitMQ, ActiveMQ).
MQ system will work as intermediate layer, which provide you loosely coupling.
Communication between modules will be implemented as posting messages to queue and listening for posting.
Also, OSGI may help you. It gives you possibility to make your application as a set of pluggable modules, which might be loaded dynamically.
As per my experience, I suggest, Use MVC pattern. Use Servlet filttersfor 1.Oauth Login.
Create service/POJOs to implement and inject each other according to your requirement for
2.User Profile Management
3.User Group creation
4.User File management
If you know Spring AOP, use. So that you can achive more dynamic integration between implementations of points 2,3, and 4.
You should split the feature in two components: API and implementation. The first one contain interfaces, the second their implementations. You pass the interface to web app controller and inject implementation via Spring or any other Dependency Injection framework. For example
web-app, UserController which handles requests from client and delegate to your components
#Component
public class UserController {
private FileManager fileManager;
#Autowired
public UserController(FileManager fileManager) {
this.fileManager = fileManager;
}
#GET("/user/{userId}/file/{fileId}")
public File getUserFile(long userId, long fileId) {
fileManager.getUserFile(userId, fileId);
}
}
file-mgt-api where you define interfaces to decouple web-app from implementation
public interface FileManager {
File getUserFile(long userId, long fileId);
}
file-mgt-impl where all the details of how to get requested file
#Component
public class FileManagerImpl implements FileManager {
#Override
public File getUserFile(long userId, long fileId) {
// get file by id from DB
// verify that provided user is the file owner
// do other useful stuff
// return the file or throw exception if something wrong
}
}
Do the same for group, profile management and other features. After that you can easily replace implementation by replacing single jar file. Your web-app is completely decoupled and don't know anything about implementation details, it only depends on interfaces.

Categories