Can not access my spring boot application by url - java

I try to access my endpoint with local host url - http://localhost:8080/all
this is my Application.java file
package com.example.MyApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication .class, args);
}
}
and this is my end point
#RestController("GetAll")
#RequestMapping("/all")
public class GetAll {
private final DataService dataService;
#Autowired
public GetAll (DataService dataService) {
this.dataService = dataService;
}
#GetMapping
public List<DataDto> getAll() {
return dataService.getAll();
}
}
and I try with this url - http://localhost:8080/all
{
"timestamp": "2022-10-06T15:27:18.574+00:00",
"status": 404,
"error": "Not Found",
"path": "/all"
}

This kind of problem might happen due to some components(like controller, service, etc) not being scanned by spring due to components and the Main class being in a different package. Here, Your main class is in com.example.MyApplication package. So If you keep all other components(like controller, service, etc) of the spring boot in the same package or sub-package then that will work as expected. If you want to keep those in the different packages you need to mention those different packages which are having spring components like controllers in the #ComponentScan annotation.
Change GetAll class's package declaration if you can keep them in the same package:
package com.example.MyApplication;
#RestController("GetAll")
#RequestMapping("/all")
public class GetAll {
private final DataService dataService;
#Autowired
public GetAll (DataService dataService) {
this.dataService = dataService;
}
#GetMapping
public List<DataDto> getAll() {
return dataService.getAll();
}
}
Reference:
https://www.baeldung.com/spring-component-scanning

Related

How do I test main app without spring security?

I have a main app that exposes endpoint like this. I have a test like this. It simply uses TestRestTemplate, calls actuator endpoint and checks health:
#ExtendWith(SpringExtension.class)
#SpringBootTest(classes = HealthDataImporterApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
#TestPropertySource(locations = "classpath:application-test.properties")
public class HealthDataImporterApplicationTest {
#Autowired
private TestRestTemplate testRestTemplate;
#LocalServerPort
private int serverPort;
#Test
public void health() {
assertThat("status", read(get("health"), "$.status").equals("UP"));
}
private String get(final String resource) {
return testRestTemplate.getForObject(String.format("http://localhost:%s/actuator/%s", serverPort, resource),
String.class);
}
}
I now added SecurityConfig class to add authentication to the app. Here is SecurityConfig class:
#EnableWebSecurity
public class SecurityConfig {
private static final String ACTUATOR_URL = "/actuator/**";
private static final String SCOPE_PREFIX = "SCOPE_";
private static final String PERMISSION_SCOPE = "scope:scope";
#Value("${auth0.audience}")
private String audience;
#Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
/*
This is where we configure the security required for our endpoints and setup our app to serve as
an OAuth2 Resource Server, using JWT validation.
*/
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.GET, ACTUATOR_URL).permitAll()
.anyRequest().hasAuthority(SCOPE_PREFIX + PERMISSION_SCOPE)
.and().cors()
.and().oauth2ResourceServer().jwt();
return http.build();
}
#Bean
JwtDecoder jwtDecoder() {
/*
By default, Spring Security does not validate the "aud" claim of the token, to ensure that this token is
indeed intended for our app. Adding our own validator is easy to do:
*/
NimbusJwtDecoder jwtDecoder = JwtDecoders.fromOidcIssuerLocation(issuer);
jwtDecoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>(JwtValidators.createDefaultWithIssuer(issuer),
new AudienceValidator(audience)));
return jwtDecoder;
}
}
Main app imports this SecurityConfig class so authentication is there. However, it fails the existing test because it complains it is missing auth0.audience and other value. It seems like it is trying to actually call auth0 url, which I don't want the test to. Otherwise, I have to put actual auth0 audience and domain which is sensitive data.
How can I disable spring security with TestRestTemplate? Is it worth to test this class at all?
As you are using spring-boot, do not override the JwtDecoder just to check audiences. Use spring.security.oauth2.resourceserver.jwt.audiences property instead (this is a comma separated list of acceptable audience).
Rather than deactivating security, I prefer to use mocked identities and include access-control in test coverage, using MockMvc (yes, even in #SpringBootTest with many components wired).
Refer to this other answer for details on how to do that in unit-test and integration-test.
Because I find request post-processors not that readable and I happen to unit-test secured components which are not controllers (like #Service or #Respository with method-security like #PreAuthorize, #PostFilter, etc.), I created a lib with test annotations for OAuth2:
#SpringBootTest(webEnvironment = WebEnvironment.MOCK)
#AutoConfigureMockMvc
class ApplicationIntegrationTest {
#Autowired
MockMvc api;
// actuator
#Test
void givenRequestIsAnonymous_whenGetStatus_thenOk() throws Exception {
api.get("/actuator/health")
.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value("UP"));
}
// secured resource
#Test
void givenRequestIsAnonymous_whenGetMachin_thenUnauthorized() throws Exception {
api.perform(get("/api/v1/machin"))
.andExpect(status().isUnauthorized());
}
#Test
#WithMockJwtAuth("SCOPE_openid", "SCOPE_scope:scope")
void givenUserIsGrantedWithExpectedAuthority_whenGetMachin_thenOk() throws Exception {
api.perform(get("/api/v1/machin"))
.andExpect(status().isOk());
}
#Test
#WithMockJwtAuth("SCOPE_openid")
void givenUserIsNotGrantedWithExpectedAuthority_whenGetMachin_thenForbidden() throws Exception {
api.perform(get("/api/v1/machin"))
.andExpect(status().isForbidden());
}
}
As comparison, the same sample with just spring-security-test:
#SpringBootTest(webEnvironment = WebEnvironment.MOCK)
#AutoConfigureMockMvc
class ApplicationIntegrationTest {
#Autowired
MockMvc api;
// actuator
#Test
void givenRequestIsAnonymous_whenGetStatus_thenOk() throws Exception {
api.perform(get("/actuator/health/liveness"))
.andExpect(status().isOk());
}
// secured resource
#Test
void givenRequestIsAnonymous_whenGetMachin_thenUnauthorized() throws Exception {
api.perform(get("/api/v1/machin"))
.andExpect(status().isUnauthorized());
}
#Test
void givenUserIsGrantedWithExpectedAuthority_whenGetMachin_thenOk() throws Exception {
api.perform(get("/api/v1/machin")
.with(jwt().jwt(jwt -> jwt.authorities(List.of(
new SimpleGrantedAuthority("SCOPE_openid"),
new SimpleGrantedAuthority("SCOPE_scope:scope"))))))
.andExpect(status().isOk());
}
#Test
void givenUserIsNotGrantedWithExpectedAuthority_whenGetMachin_thenForbidden() throws Exception {
api.perform(get("/api/v1/machin")
.with(jwt().jwt(jwt -> jwt.authorities(List.of(
new SimpleGrantedAuthority("SCOPE_openid"))))))
.andExpect(status().isForbidden());
}
}
In JHipster, we generate a TestSecurityConfiguration class that mocks the JwtDecoder bean so no identity provider is needed. You can see the code here. I've copied it below for your convenience.
package com.auth0.flickr2.config;
import static org.mockito.Mockito.mock;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.jwt.JwtDecoder;
/**
* This class allows you to run unit and integration tests without an IdP.
*/
#TestConfiguration
#Import(OAuth2Configuration.class)
public class TestSecurityConfiguration {
#Bean
ClientRegistration clientRegistration() {
return clientRegistrationBuilder().build();
}
#Bean
ClientRegistrationRepository clientRegistrationRepository(ClientRegistration clientRegistration) {
return new InMemoryClientRegistrationRepository(clientRegistration);
}
private ClientRegistration.Builder clientRegistrationBuilder() {
Map<String, Object> metadata = new HashMap<>();
metadata.put("end_session_endpoint", "https://jhipster.org/logout");
return ClientRegistration
.withRegistrationId("oidc")
.issuerUri("{baseUrl}")
.redirectUri("{baseUrl}/{action}/oauth2/code/{registrationId}")
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.scope("read:user")
.authorizationUri("https://jhipster.org/login/oauth/authorize")
.tokenUri("https://jhipster.org/login/oauth/access_token")
.jwkSetUri("https://jhipster.org/oauth/jwk")
.userInfoUri("https://api.jhipster.org/user")
.providerConfigurationMetadata(metadata)
.userNameAttributeName("id")
.clientName("Client Name")
.clientId("client-id")
.clientSecret("client-secret");
}
#Bean
JwtDecoder jwtDecoder() {
return mock(JwtDecoder.class);
}
#Bean
OAuth2AuthorizedClientService authorizedClientService(ClientRegistrationRepository clientRegistrationRepository) {
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
}
}
This class is then referenced in the test and overrides the SecurityConfig.
#SpringBootTest(classes = { Flickr2App.class, TestSecurityConfiguration.class })
The full project repo is at https://github.com/oktadev/auth0-full-stack-java-example.

Get NOT_FOUND with Spring Boot?

I'm new to Spring framework.
I try to make a simple web server application with Spring but I got 404 Not Found when I call url with Postman.
package com.leoaslan.doctorfinder;
//..import
#SpringBootApplication
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
#ComponentScan({"com.delivery.request"})
#EntityScan("com.delivery.domain")
#EnableJpaRepositories("com.delivery.repository")
public class DoctorfinderApplication {
public static void main(String[] args) {
SpringApplication.run(DoctorfinderApplication.class, args);
}
}
package com.leoaslan.doctorfinder.controller;
//import
#RestController
#RequestMapping("/api")
public class LoginController {
private final Logger log = LoggerFactory.getLogger(LoginController.class);
#Autowired
LoginService loginService;
#GetMapping("/auth/login")
ResponseEntity<?> login(HttpServletRequest request) {
System.out.println("OK");
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
}
I haven't configured anything yet in application.properties.
Thanks for any helps
Your Controller class is not being scanned, so just try to add the proper package of your controllers on your #ComponentScan
#ComponentScan({"com.delivery.request", "com.leoaslan.doctorfinder.controller"})
Actually, do you really have those packages (com.delivery.request, com.delivery.domain, com.delivery.repository) on your application ? They look suspiciously copy/pasted and they will not do anything unless you change them where your classes really are.

Spring Boot does not recognize MongoDB RestController class

I am new to MongoDB and I am trying to use it with my SpringBoot application. I have followed my tutorials online and have downloaded their code and got it execute.
However for whatever reason my project fails to be able to print out
RequestMappingHandlerMapping : Mapped “{[/findAllBooks/{id}],methods=[GET]}”
I was wondering if anyone would be able to advise me if it is due to the nature of my project structure .
I wasn’t sure if my SpringBootMain could see my Controller class.
My project structure is best viewed here
https://github.com/emuldrew855/backend/tree/A/B-Testing/src/main/java/com/ebay/queens/demo
My Controller class
package com.ebay.queens.demo.resource;
#RestController
#RequestMapping("/v2")
public class UserController {
#Autowired
private UserRepository userRepository;
#PostMapping("/AddUser")
public String saveUser(#RequestBody User user) {
userRepository.save(user);
return "Added user with id: " + user.getId();
}
#GetMapping("/all")
public List<User> getAll(){
List<User> users = this.userRepository.findAll();
return users;
}
}
My main class
package com.ebay.queens.demo;
#SpringBootConfiguration
#SpringBootApplication
public class SpringBootMain implements CommandLineRunner {
#Autowired
private TokenUtilityClass tokenUtilityClass;
#Bean ResourceConfig resourceConfig() {
return new ResourceConfig().registerClasses(Version1Api.class, Login.class, SignUp.class, Paypal.class); }
#Override
public void run(String... args) throws Exception {
// test.authenticationToken();
}
public static void main(String[] args) {
SpringApplication.run(SpringBootMain.class, args);
}
}
I've figured out why is not working... You are using 2 different WebService API which are incompatible...
Spring-Boot has native API to work with API Rest with #RestController annotation. You don't need to use Glassfish server.
Solution #1
From SpringBootMain remove #Bean ResourceConfig resourceConfig() {...}. Now, you API /v2 will work as expected.
Your API /v1 won't work because it uses other library. You need to change #Path to #GetMapping or #PostMapping and add #RestController into your Version1Api class.
Solution #2
You ignore Spring-Boot native Rest API and implement Glassfish Server.
Add UserController.class reference
#Bean ResourceConfig resourceConfig() {
return new ResourceConfig().registerClasses(Version1Api.class, Login.class, SignUp.class, Paypal.class, UserController.class); }
For UserController change #RestController to #Path("/v2")
#Path("/v2")
public class UserController {
#Autowired
private UserRepository userRepository;
#POST
#Path("/AddUser")
#Produces(MediaType.TEXT_PLAIN)
public String saveUser(#RequestBody User user) {
userRepository.save(user);
return "Added user with id: " + user.getId();
}
#GET
#Path("/all")
#Produces(MediaType.APPLICATION_JSON)
public List<User> getAll(){
List<User> users = this.userRepository.findAll();
return users;
}
}
Now both API will work as expected

Spring AOP blocks RestController

I try to learn Spring AOP. I've created simple spring boot project in IDEA.
Service.java
package com.example.demo.service;
//imports..
public interface Service {
public DataEntity getData();
}
ServiceImpl.java
package com.example.demo.service;
//imports..
#RestController("service")
public class ServiceImpl implements Service {
#RequestMapping(value="/test", method= RequestMethod.GET)
public DataEntity getData() {
DataEntity data = new DataEntity();
data.setData("SomeString");
return data;
}
}
ServiceCallingAspect.java
package com.example.demo.aspects;
//imports..
#Aspect
#EnableAspectJAutoProxy
#Component
public class ServiceCallingAspect {
private Log log = LogFactory.getLog(ServiceCallingAspect.class);
#AfterReturning("execution(public * com.example.demo.service.*.*(..))")
public void logBeforeRestCall(JoinPoint pjp) throws Throwable {
log.info(" POST REST call " + pjp);
}
}
DemoApplication.java
package com.example.demo;
//..
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
So when I try to call my rest service on http://localhost:8080/test, I get something like that.
{
"timestamp": 1514109432038,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/test"
}
When I disable my aspect (just comment all annotations in ServiceCallingAspect.java) the service works perfectly. Can you show me where I am wrong?
Change #EnableAspectJAutoProxy to #EnableAspectJAutoProxy(proxyTargetClass=true).
#Aspect
#EnableAspectJAutoProxy(proxyTargetClass=true)
#Component
public class ServiceCallingAspect {
.....
}

Spring boot not displaying first view

I'm building a spring boot application. My problem is that when I run the project, my login page is not shown. This is my code:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class RestLogin {
#RequestMapping("/")
public String login() {
return "login";
}
}
I get only a white page and "login" is written in it. When I try to change the #RestController with #Controller I get this GET http://localhost:8080/ 404 (). My login.html page is located under the webapp>tpl>login.html
How can I display my login page?
Edit
This is my application class
#SpringBootApplication
public class ExampleApplication extends SpringBootServletInitializer {
private static Logger logger = LoggerFactory.getLogger(ExampleApplication.class);
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(ExampleApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}
I dont know your configuration but:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests()
.antMatchers("/**").permitAll();
http.authorizeRequests().antMatchers("/**").permitAll();
}
}
In the Application.properties file add:
spring.mvc.view.suffix: .html
Change #RestController to #Controller for RestLogin class. Also put your html file inside the static folder inside resources folder.
You need an application class with a main method. See this tutorial.
Here's a snippet:
package hello;
import java.util.Arrays;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}
}
This is the normal behavior.
New version of Spring web comes with #RestController annotation which nothing but #Controller + #ResponseBody. So when you have a return statement in a method you must use #RestController or annotate your method with #ResponseBody.
Here the problem is that Spring don't know a lot about the http method type, can you please try to use #GetMapping("/") to combinbe path and method at the same time.
According to your posted code and your description, you're getting an expected behavior.
When you annotate your controller with #RestController, that means that your methods on that controller will try to return their result as JSON.
According to your code:
#RestController
public class RestLogin {
#RequestMapping("/")
public String login() {
return "login";
}
}
You're returning the String "login", that's why you're getting empty white page with the word login as JSON
If you will change the #RestController to #Controller then it no longer will return your string as JSON,
but Spring will try to figure out from the that "login" string a view, and for that you'll need to add a view resolver bean to your project.

Categories