Problems setting up Spring security in existing MVC project - spring

I'm trying to add Spring security to an existing Spring MVC project. I'm using this as a guide:
http://docs.spring.io/spring-security/site/docs/current/guides/html5//hellomvc.html
However, I can't get the project to display the login screen. I copied SecurityConfig.java and MessageSecurityWebApplicationInitializer.java verbatim, when I turn boot logging to DEBUG, I see this:
o.s.b.c.e.ServletContextInitializerBeans : Created Filter initializer for bean 'springSecurityFilterChain'; order=2147483647, resource=class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]
Which suggests that MessageSecurityWebApplicationInitializer is never being looked at. Sure enough, if I create a default constructor and set a breakpoint, it's never getting hit.
Interestingly, SecurityConfig.configureGlobal is called, which seems like the call that should be setting up the login screen.
So what steps need to happen to make MessageSecurityWebApplicationInitializer do its thing? I'm still trying to understand how Spring handles dependency injection, etc.--what about this class declaration should cause this to get picked up during boot (I would have expected some sort of annotation):
public class MessageSecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
I can't share much other code unfortunately, but this is the Application file:
#ComponentScan(basePackages={"..."})
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class, SpringBootWebSecurityConfiguration.class})
#Configuration
public class Application extends SpringBootServletInitializer {
/**
* The main() method is required by the framework.
*
* #param args
* #throws IOException
*/
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
The one thing that the sample has that this project doesn't is the MessageWebApplicationInitializer class, but to me it looks like that functionality should be picked up by my Application class.
Thanks!

You must add annotations #Configuration and #EnableWebSecurity to your MessageSecurityWebApplicationInitializer and take care that its picked up by spring. Than it should work.

So it turns out the problem was these lines in my gradle build:
compile(group: "org.springframework.boot", name: "spring-boot-starter-actuator", version: "1.2.3.RELEASE")
compile(group: "org.springframework.boot", name: "spring-boot-starter-web", version: "1.2.3.RELEASE")
compile(group: "org.springframework.boot", name: "spring-boot-starter-test", version: "1.2.3.RELEASE")
compile(group: "org.springframework.boot", name: "spring-boot-starter-jdbc", version: "1.2.3.RELEASE")
It would be great if anyone could shed some insight into why these lines would break the security setup.

Related

An attempt was made to call the method spring kafka

I am having a bit of trouble integrating spring-kafka with spring-boot. I am using spring boot v2.1 with spring-kafka v2.2 (which should be compatible according to the matrix).
I have seen multiple similar questions but none of them fixes my problem.
The error from the logs:
***************************
APPLICATION FAILED TO START
***************************
Description:
An attempt was made to call the method org.springframework.kafka.listener.AbstractMessageListenerContainer.getContainerProperties()Lorg/springframework/kafka/listener/config/ContainerProperties; but it does not exist. Its class, org.springframework.kafka.listener.AbstractMessageListenerContainer, is available from the following locations:
jar:file:/C:/Users/Ali/.m2/repository/org/springframework/kafka/spring-kafka/2.2.0.RELEASE/spring-kafka-2.2.0.RELEASE.jar!/org/springframework/kafka/listener/AbstractMessageListenerContainer.class
It was loaded from the following location:
file:/C:/Users/Ali/.m2/repository/org/springframework/kafka/spring-kafka/2.2.0.RELEASE/spring-kafka-2.2.0.RELEASE.jar
Action:
Correct the classpath of your application so that it contains a single, compatible version of org.springframework.kafka.listener.AbstractMessageListenerContainer
2022-06-28 13:21:16,716 INFO [,,,] [main] ThreadPoolTaskExecutor[shutdown]: Shutting down ExecutorService 'applicationTaskExecutor'
My dependency in the pom:
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
My code:
#Component
public class MyListenerComponent {
#KafkaListener(topics="myTopic")
public void Listen(MyModelClass obj) {
//do stuff (nothing complicated, basic java stuff)
}
}
My Application:
#Configuration
#SpringBootApplication
#EnableKafka
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I can't seem to find examples/samples dating back to v2.2.
I am not using any other listeners or containers like JMS or MQ, so there should be no conflicts (seen a similar question where RabbitMQ was causing conflicts).
The error only seems to happen when I use the KafkaListener annotation, Is there a fix or alternative way to deal with listeners?
In any case; those versions are no longer supported; even commercially https://spring.io/projects/spring-boot#support and https://spring.io/projects/spring-kafka#support let alone OSS.
The root cause is definitely a mis-matched version because that class (ContainerProperties) was moved from config to listener in 2.2.
An attempt was made to call the method org.springframework.kafka.listener.AbstractMessageListenerContainer.getContainerProperties()Lorg/springframework/kafka/listener/config/ContainerProperties; but it does not exist. Its class, org.springframework.kafka.listener.AbstractMessageListenerContainer, is available from the following locations:
Whatever is calling getContainerProperties() was compiled against an earlier version.

404 error when using modules from controller layer with spring boot

I have a projects that contains modules that represents the layers (dao, service, controllers, models). I am using #ComponentScan but steel when I access the rest api that my controllers provide I get 404 error. From what i was Reading both my main class and my controllers should be in the same package or to tell #ComponentScan() which packages to scan. I tried it all but it does not recognize the classes inside my modules - I think this is the main problem but I’m not sure. I would like to get some help and understand why this in happening. Thank you
#EnableMongoAuditing
#SpringBootApplication
#ComponentScan({"com.vimalesh"})
#EnableWebFlux
#EnableReactiveMongoRepositories("com.vimalesh.data.repository")
public class FundsApplication {
public static void main(String[] args) {
SpringApplication.run(FundsApplication.class, args);
}
}
Mention the package name that you want to scan like above.
Thanks

Spring boot AMQP and Spring Hadoop together ends up with missing EmbeddedServletContainerFactory bean

I have two small apps, one uses spring-boot-starter-amqp, other uses spring-data-hadoop-boot. I can run them separately without any problems.
When I join them together, app start fails with exception: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
My main class is pretty much generic and it works fine for both of them separately:
#PropertySource("file:conf/app.properties")
#SpringBootApplication
public class Job {
public static void main(String[] args) throws Exception {
SpringApplication.run(Job.class, args);
}
}
I am at lost here. AFAIK #SpringBootApplication contains all annotations needed, including auto configuration and components scanning. I've had no need to configure web environment as I am not using it. Why do I need to do it when both dependencies are in class path, and how do I fix it?
UPDATE
I dug a little bit in the Spring Boot code. Main problem is that SpringApplication.deduceWebEnvironment() automatically detects what kind of environment should be configured based on existence of certain classes in class path.
For web environment two classes are being checked. When both of them are in class path, web environment is detected which requires proper configuration, obviously.
javax.servlet.Servlet
org.springframework.web.context.ConfigurableWebApplicationContext
spring-boot-starter-amqp:1.3.1.RELEASE contains ConfigurableWebApplicationContext, and spring-data-hadoop-boot:2.3.0.RELEASE-cdh5 contains Servlet (in native Hadoop libs).
Now, when run alone, one of above classes is missing in both cases, which results in web environment not being set.
But when I use both of them - both classes can be found. Web environment is detected, false positive, and it requires configuration, which I am not able (and don't want) to provide.
So question now is - can I force non web environment, even when I have those classes in class path? Or is there any other way to solve the issue? (other than excluding them from Gradle dependencies)
Solved.
Following this question: How to prevent spring-boot autoconfiguration for spring-web?
I run application as follows.
#PropertySource("file:conf/app.properties")
#SpringBootApplication
public class Job {
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(Job.class).web(false).run(args);
}
}
Answers to above question also suggested to use property spring.main.web_environment=false or annotation #EnableAutoConfiguration(exclude = WebMvcAutoConfiguration.class). Both solutions haven't worked for me. Only programmatic solution works in my case.

Add property to entity in spring data REST

I am trying out the ResourceProcessor interface in Spring Data REST. I don't think my Processor ever gets called. No error message either.
Here is my processor (in Groovy):
#Autowired
PersonService personService
#Override
public Resource<Person> process(Resource<Person> resource) {
resource.content.isAdult = personService.isAdult(resource.content)
// sanity check: does this link get added?? (NOPE!!)
resource.add(new Link("http://localhost:8080/people", "added-link"))
log.info "## resource.content.isAdult ==> ${resource.content}"
return resource
}
Any help would be most appreciated!! You can see the entire project here in GitHub: https://github.com/txiasummer/spring-data-rest-examples
Finally got it to work! It turns out to be something completely trivial and I can't believe I missed it. I have a PersonProcessor classes which implements Spring's native ResourceProcessor interface. But PersonProcessor is still just a basic class that must be injected by Spring!! I think I was getting it confused with #Projection, which will be recognized automatically and does not need to be injected explicitly.
I addd #ComponentScan to my Application.groovy and now everything is working swimmingly. Alternatively, you an also manually define the PersonProcessor class and its service PersonService class as #Bean in Application.groovy. Again, you can see the whole project here: https://github.com/txiasummer/spring-data-rest-examples

No value has been specified for property 'mainClassName'

I am trying to build a project with
apply plugin: 'spring-boot'
But it throws an exception at the step startScripts
:common:compileJava UP-TO-DATE
:common:processResources UP-TO-DATE
:common:classes UP-TO-DATE
:common:jar UP-TO-DATE
:common:findMainClass
:common:startScripts FAILED
FAILURE: Build failed with an exception.
* What went wrong:
A problem was found with the configuration of task ':common:startScripts'.
> No value has been specified for property 'mainClassName'.
But I really do not need a main Class for this module. How should I settle this?
There's an open ticket about this issue on Spring-Boot's GitHub: https://github.com/spring-projects/spring-boot/issues/2679. There are couple things you can do according to discussion:
Remove spring-boot plugin from buildscript section. This will remove special Gradle tasks from build flow.
Assign mainClassName to some random string. It's not pretty but as far as this is not runnable app you probably don't care about main class.
There are some more bulky ways to solve this listed by the link if you want to try them.
Hope this helps.
You need a main method which calls SpringApplication.run(...). Like this:
public static void main(String[] args) throws Exception {
SpringApplication.run(Example.class, args);
}
In the Gettings started guide is a paragraph about the main method:
The final part of our application is the main method. This is just a
standard method that follows the Java convention for an application
entry point. Our main method delegates to Spring Boot’s
SpringApplication class by calling run. SpringApplication will
bootstrap our application, starting Spring which will in turn start
the auto-configured Tomcat web server. We need to pass Example.class
as an argument to the run method to tell SpringApplication which is
the primary Spring component. The args array is also passed through to
expose any command-line arguments.
I recommend to create a Application class where it all starts:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
But, perhaps you should start with the Quick start guide at first.
I have the following at the end of my build.gradle to define the name of the main class.
I also use gradlew bootjar instead of gradlew build.
bootJar {
mainClassName = 'com.spring.xx.app.App'
}

Resources