Spring & Keycloak - null principal - java

I am trying to configure my Spring Boot application to use Keycloak as SSO.
I am following standard tutorials in this topic:
First add dependency
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>13.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Second, fill properties
# Keycloak
keycloak.realm = Mixeway
keycloak.auth-server-url = http://localhost:8180/auth
keycloak.ssl-required = external
keycloak.resource = MixewayApp
keycloak.credentials.secret = secret
keycloak.use-resource-role-mappings = false
keycloak.bearer-only = false
keycloak.security-constraints[0].authRoles[0]=USER
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/v2/auth/keycloak
Third create controller to handle authentication
#GetMapping(value = "/v2/auth/keycloak")
public void authUsingKeycloak(Principal principal){
log.info("user {} logged using keycloak", principal.getName());
}
Authentication works properly. I can see logs:
2021-12-30 10:18:48.213 DEBUG 6947 --- [nio-8443-exec-3] o.k.adapters.OAuthRequestAuthenticator : Verifying tokens
2021-12-30 10:18:48.265 DEBUG 6947 --- [nio-8443-exec-3] o.k.a.rotation.JWKPublicKeyLocator : Realm public keys successfully retrieved for client MixewayApp. New kids: [mpkD1RwCaaIbp8tN-a9__hlc03UpxrQ8SE5atlDrF78]
2021-12-30 10:18:48.270 DEBUG 6947 --- [nio-8443-exec-3] o.k.adapters.OAuthRequestAuthenticator : Token Verification succeeded!
2021-12-30 10:18:48.277 DEBUG 6947 --- [nio-8443-exec-3] o.k.a.rotation.JWKPublicKeyLocator : Realm public keys successfully retrieved for client MixewayApp. New kids: [mpkD1RwCaaIbp8tN-a9__hlc03UpxrQ8SE5atlDrF78]
2021-12-30 10:18:48.277 DEBUG 6947 --- [nio-8443-exec-3] o.k.adapters.OAuthRequestAuthenticator : successful authenticated
2021-12-30 10:18:48.283 DEBUG 6947 --- [nio-8443-exec-3] o.k.adapters.RequestAuthenticator : User '343050ef-bc48-48ae-af93-5dd3f0830956' invoking 'https://localhost:8443/v2/auth/keycloak?state=d1ebaf04-c0fd-4415-8f70-56b68e9f8485&session_state=e2e280a0-428d-4481-99c6-f45cfa171f4c&code=da46d2ee-14b5-45ef-a15f-6a69e196f092.e2e280a0-428d-4481-99c6-f45cfa171f4c.0b00edfd-1474-42ec-a2df-f2754b830dc6' on client 'MixewayApp'
2021-12-30 10:18:48.283 DEBUG 6947 --- [nio-8443-exec-3] o.k.adapters.RequestAuthenticator : AUTHENTICATED
2021-12-30 10:18:48.291 DEBUG 6947 --- [nio-8443-exec-4] o.k.adapters.PreAuthActionsHandler : adminRequest https://localhost:8443/v2/auth/keycloak
2021-12-30 10:18:48.291 DEBUG 6947 --- [nio-8443-exec-4] o.k.adapters.RequestAuthenticator : AUTHENTICATED: was cached
2021-12-30 10:18:48.291 DEBUG 6947 --- [nio-8443-exec-4] .k.a.t.AbstractAuthenticatedActionsValve : AuthenticatedActionsValve.invoke /v2/auth/keycloak
However I am getting NullPointer Exception due to null Principal object. Can anyone give me a hint how to configure keycloak auth in spring so that principal object is set properly?
EDIT
after rewriting controller to
#GetMapping(value = "/v2/auth/keycloak")
public void authUsingKeycloakGet(HttpServletRequest request){
KeycloakPrincipal principal=(KeycloakPrincipal) request.getUserPrincipal();
KeycloakSecurityContext session = principal.getKeycloakSecurityContext();
AccessToken accessToken = session.getToken();
}
and debugging application I am able to see principal in HttpServletRequest but both principal and request.getUserPrincipal() is still null:

As it is in controller level and you are creating an endPoint, you need to use #RequestBody annotation for the body inputs, #RequestParam annotation for request parameters (i.e. yourEndPoint?id=1) or #PathVariable for path variables in the endPoint (i.e. yourEndPoint/1).

Related

No adapter for endpoint Spring WS SOAP

I have a very strange problem.
I'm trying send request to my SOAP-app, and I get this logs (logging-level=trace):
2022-06-18 12:08:33.341 DEBUG 11612 --- [nio-8080-exec-1] yloadRootAnnotationMethodEndpointMapping : Looking up endpoint for [{localhost/soap}GetAllUser]
2022-06-18 12:08:33.341 DEBUG 11612 --- [nio-8080-exec-1] o.s.w.soap.server.SoapMessageDispatcher : Endpoint mapping [org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping#113c4ad6] maps request to endpoint [public localhost.soap.GetAllUserResponse com.driypeen.userServiceSOAP.endpoint.UserEndpoint.getAllUsers(localhost.soap.GetAllUserRequest)]
Testing endpoint adapter [org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter#1f6f0fe2]
2022-06-18 12:08:33.343 TRACE 11612 --- [nio-8080-exec-1] o.s.w.s.e.a.DefaultMethodEndpointAdapter : Testing if argument resolver [org.springframework.ws.server.endpoint.adapter.method.dom.DomPayloadMethodProcessor#352c3d70] supports [class localhost.soap.GetAllUserRequest]
2022-06-18 12:08:33.344 TRACE 11612 --- [nio-8080-exec-1] o.s.w.s.e.a.DefaultMethodEndpointAdapter : Testing if argument resolver [org.springframework.ws.server.endpoint.adapter.method.MessageContextMethodArgumentResolver#4c13ca07] supports [class localhost.soap.GetAllUserRequest]
2022-06-18 12:08:33.344 TRACE 11612 --- [nio-8080-exec-1] o.s.w.s.e.a.DefaultMethodEndpointAdapter : Testing if argument resolver [org.springframework.ws.server.endpoint.adapter.method.SourcePayloadMethodProcessor#7d17906] supports [class localhost.soap.GetAllUserRequest]
2022-06-18 12:08:33.344 TRACE 11612 --- [nio-8080-exec-1] o.s.w.s.e.a.DefaultMethodEndpointAdapter : Testing if argument resolver [org.springframework.ws.server.endpoint.adapter.method.XPathParamMethodArgumentResolver#97beeaf] supports [class localhost.soap.GetAllUserRequest]
2022-06-18 12:08:33.345 TRACE 11612 --- [nio-8080-exec-1] o.s.w.s.e.a.DefaultMethodEndpointAdapter : Testing if argument resolver [org.springframework.ws.soap.server.endpoint.adapter.method.SoapMethodArgumentResolver#5d68954d] supports [class localhost.soap.GetAllUserRequest]
2022-06-18 12:08:33.345 TRACE 11612 --- [nio-8080-exec-1] o.s.w.s.e.a.DefaultMethodEndpointAdapter : Testing if argument resolver [org.springframework.ws.soap.server.endpoint.adapter.method.SoapHeaderElementMethodArgumentResolver#f793f15] supports [class localhost.soap.GetAllUserRequest]
2022-06-18 12:08:33.345 TRACE 11612 --- [nio-8080-exec-1] o.s.w.s.e.a.DefaultMethodEndpointAdapter : Testing if argument resolver [org.springframework.ws.server.endpoint.adapter.method.jaxb.XmlRootElementPayloadMethodProcessor#3ec7eb5] supports [class localhost.soap.GetAllUserRequest]
2022-06-18 12:08:33.351 TRACE 11612 --- [nio-8080-exec-1] o.s.w.s.e.a.DefaultMethodEndpointAdapter : Testing if argument resolver [org.springframework.ws.server.endpoint.adapter.method.jaxb.JaxbElementPayloadMethodProcessor#5534e6f1] supports [class localhost.soap.GetAllUserRequest]
2022-06-18 12:08:33.352 TRACE 11612 --- [nio-8080-exec-1] o.s.w.s.e.a.DefaultMethodEndpointAdapter : Testing if argument resolver [org.springframework.ws.server.endpoint.adapter.method.dom.JDomPayloadMethodProcessor#4c6fc3e7] supports [class localhost.soap.GetAllUserRequest]
2022-06-18 12:08:33.352 TRACE 11612 --- [nio-8080-exec-1] o.s.w.s.e.a.DefaultMethodEndpointAdapter : Testing if argument resolver [org.springframework.ws.server.endpoint.adapter.method.StaxPayloadMethodArgumentResolver#aa8dce8] supports [class localhost.soap.GetAllUserRequest]
2022-06-18 12:08:33.353 DEBUG 11612 --- [nio-8080-exec-1] o.s.w.soap.server.SoapMessageDispatcher : Testing endpoint adapter [org.springframework.ws.server.endpoint.adapter.PayloadEndpointAdapter#ab2009f]
2022-06-18 12:08:33.353 DEBUG 11612 --- [nio-8080-exec-1] s.e.SoapFaultAnnotationExceptionResolver : Resolving exception from endpoint [public localhost.soap.GetAllUserResponse com.driypeen.userServiceSOAP.endpoint.UserEndpoint.getAllUsers(localhost.soap.GetAllUserRequest)]: java.lang.IllegalStateException: No adapter for endpoint [public localhost.soap.GetAllUserResponse com.driypeen.userServiceSOAP.endpoint.UserEndpoint.getAllUsers(localhost.soap.GetAllUserRequest)]: Is your endpoint annotated with #Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?
2022-06-18 12:08:33.354 DEBUG 11612 --- [nio-8080-exec-1] o.s.w.s.s.e.SimpleSoapExceptionResolver : Resolving exception from endpoint [public localhost.soap.GetAllUserResponse com.driypeen.userServiceSOAP.endpoint.UserEndpoint.getAllUsers(localhost.soap.GetAllUserRequest)]: java.lang.IllegalStateException: No adapter for endpoint [public localhost.soap.GetAllUserResponse com.driypeen.userServiceSOAP.endpoint.UserEndpoint.getAllUsers(localhost.soap.GetAllUserRequest)]: Is your endpoint annotated with #Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?
2022-06-18 12:08:33.370 DEBUG 11612 --- [nio-8080-exec-1] o.s.w.soap.server.SoapMessageDispatcher : Endpoint invocation resulted in exception - responding with Fault
It turns out that the server finds the endpoint, but does not find the adapter?
So, i written this:
#Autowired
List<EndpointAdapter> adapters;
#PostConstruct
public void a () {
log.info("ADAPTERS:");
adapters.forEach(System.out::println);
}
And get this output:
2022-06-18 12:07:03.106 INFO 11612 --- [ main] c.d.u.endpoint.UserEndpoint : ADAPTERS:
org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter#1f6f0fe2
org.springframework.ws.server.endpoint.adapter.PayloadEndpointAdapter#ab2009f
My XSD file contains this:
<xs:element name="GetAllUserRequest">
<xs:complexType>
<xs:sequence>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetAllUserResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="users" type="tns:UserWithoutRole" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Generated classes look like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(
name = ""
)
#XmlRootElement(
name = "GetAllUserRequest"
)
public class GetAllUserRequest {
public GetAllUserRequest() {
}
}
My request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:gs="localhost/soap">
<soapenv:Header/>
<soapenv:Body>
<gs:GetAllUser/>
</soapenv:Body>
</soapenv:Envelope>
Endpoint class:
#Endpoint
#Slf4j
public class UserEndpoint {
private static final String NAMESPACE_URI = "localhost/soap";
private UserService userService;
#Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
#Autowired
List<EndpointAdapter> adapters;
#PostConstruct
public void a () {
log.info("ADAPTERS:");
adapters.forEach(System.out::println);
}
#PayloadRoot(localPart = "GetAllUser", namespace = NAMESPACE_URI)
#ResponsePayload
public GetAllUserResponse getAllUsers(#RequestPayload GetAllUserRequest request) {
log.info("GET ALL USERS");
GetAllUserResponse response = new GetAllUserResponse();
response.getUsers().addAll(userService.findAll());
return response;
}
}
WebServiceConfig:
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
#Bean(name = "soap")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("SoapPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("localhost/soap");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}
#Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("userServiceSOAP.xsd"));
}
#Bean
public EndpointAdapter messageEndpointAdapter() {
return new PayloadEndpointAdapter();
}
}
Why does none of the adapters support my endpoint?
Thanks!
I faced the same issue. In my case it was related to using Jakarta XML bind.
When I change it to Javax instead of Jakarta everything works fine.
So when you check imports in your generated sources, it should be smth like that:
import javax.xml.bind.annotation.XmlRootElement;
Additional dependencies for Java 8+ listed below:
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>
Note if your Java version is 8 or less, this guide works fine w/o changes, because Java 8 is still shipped with JAXB implementation.
I saw that Spring 5 doesn't support Jakarta, they planned to add support in future 6 version.

How to use Spring Boot WebClient to access an OAuth2 secured REST API

I have rest api secured with oauth2 that I need to consume. The Authorization-grant-type is password. After obtaining access token I should request secured resource with it. The main idea is I need to acquire and refresh the access token automatically when it expires. I think it should not be kept somewhere in the session or database. Because spring security 5.2.* gives this oportunity out of the box. To do this I followed this post.
When I run the app it keeps saying that I am not authorized even if I specified the properties in application.yml.
021-07-06 16:33:15.292 INFO 25636 --- [ main] d.e.o.Oauth2clientApplication : Starting Oauth2clientApplication using Java 15.0.1 on F-LAPASOV with PID 25636 (C:\Users\f.lapasov\IdeaProjects\logwso2\oauth2client\target\classes started by f.lapasov in C:\Users\f.lapasov\IdeaProjects\logwso2\oauth2client)
2021-07-06 16:33:15.294 INFO 25636 --- [ main] d.e.o.Oauth2clientApplication : No active profile set, falling back to default profiles: default
2021-07-06 16:33:15.924 INFO 25636 --- [ main] ctiveUserDetailsServiceAutoConfiguration :
Using generated security password: 8bd88c3a-37c6-45b6-9721-ceca17e8e0bf
2021-07-06 16:33:16.173 INFO 25636 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 9797
2021-07-06 16:33:16.181 INFO 25636 --- [ main] d.e.o.Oauth2clientApplication : Started Oauth2clientApplication in 1.168 seconds (JVM running for 1.613)
2021-07-06 16:33:16.359 INFO 25636 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-07-06 16:33:16.375 ERROR 25636 --- [ main] o.s.boot.SpringApplication : Application run failed
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:794) ~[spring-boot-2.5.2.jar:2.5.2]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:775) ~[spring-boot-2.5.2.jar:2.5.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:345) ~[spring-boot-2.5.2.jar:2.5.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.2.jar:2.5.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.2.jar:2.5.2]
at dev.egov.oauth2client.Oauth2clientApplication.main(Oauth2clientApplication.java:17) ~[classes/:na]
Caused by: org.springframework.web.reactive.function.client.WebClientResponseException$Unauthorized: 401 Unauthorized from GET http://ip:808/app/rest/v2/services/student/get?pin=123456789
at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:198) ~[spring-webflux-5.3.8.jar:5.3.8]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ 401 from GET http://ip:808/app/rest/v2/services/student/get?pinfl=1234567898 [DefaultWebClient]
Stack trace:
at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:198) ~[spring-webflux-5.3.8.jar:5.3.8]
*******************************
Snippet of the pom.xml file is given below
**************
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
**************
Propert file looks like below:
spring:
security:
oauth2:
client:
registration:
bael:
client-id: client
client-secret: secret
authorization-grant-type: password
provider:
bael:
token-uri: http://ip:port/app/rest/v2/oauth/token
server:
port: 9797
Configuration class for webClient:
#Configuration
public class WebClientConfig {
#Bean
WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations,
new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("bael");
return WebClient.builder()
.filter(oauth)
.build();
}
}
My service class:
#Service
public class WebClientService {
#Autowired
private WebClient webClient;
public String callApi(ApiRequest apiRequest) {
return webClient
.get()
.uri("http://ip:port/app/rest/v2/services/student/get",uriBuilder ->
uriBuilder
.queryParam("pin", apiRequest.getPinfl()).build()
)
.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("bael"))
.retrieve()
.bodyToMono(String.class).block();
}
}

Spring Boot : javax.persistence.TransactionRequiredException: Executing an update/delete query When Using #Transactional Annotation

I am working on Spring Boot (v1.5.22.RELEASE) and Hibernate 5.4.20.Final [pom.xml attached bellow]. Also tried with Spring Boot (v2.2.2) but I am getting same error.
In my project the database is dynamic. Based on the request, the database is changed.
I am using SessionBuilderImpl class to set database and get Current Session.
When trying to update the table [Using HQL or NativeSQL] , the following exception is thrown:
ERROR AppDeploymentHistoryDaoImpl ERROR WHILE UPDATING APP DEPLOYMENT HISTORY STATUS { SET `is_current_exec` = 0 } IN DATABASE { AppDeploymentHistoryDaoImpl.updateAllStatus }javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:413)
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1608)
at com.testcompany.app.fw.amt.entity.daoimpl.AppDeploymentHistoryDaoImpl.updateAllStatus(AppDeploymentHistoryDaoImpl.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy69.updateAllStatus(Unknown Source)
at com.testcompany.app.fw.amt.entity.serviceimpl.AppDeploymentHistoryServiceImpl.updateAllStatus(AppDeploymentHistoryServiceImpl.java:55)
at com.testcompany.app.fw.amt.entity.serviceimpl.AppDeploymentHistoryServiceImpl$$FastClassBySpringCGLIB$$2b450460.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:736)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:283)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:671)
at com.testcompany.app.fw.amt.entity.serviceimpl.AppDeploymentHistoryServiceImpl$$EnhancerBySpringCGLIB$$8b3a1110.updateAllStatus(<generated>)
at com.testcompany.app.fw.amt.core.AppHandler.resetAppDeploymentHsitoryStatus(AppHandler.java:121)
at com.testcompany.app.fw.amt.core.AppHandler.setBasicSetup(AppHandler.java:80)
at com.testcompany.app.fw.amt.core.AppUninstallInitiator.setBasicSetup(AppUninstallInitiator.java:45)
at com.testcompany.app.fw.amt.core.AppUninstallInitiator$$FastClassBySpringCGLIB$$77c48f3c.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:667)
at com.testcompany.app.fw.amt.core.AppUninstallInitiator$$EnhancerBySpringCGLIB$$69685b24.setBasicSetup(<generated>)
at com.testcompany.app.fw.amt.rmq.UndeploymentQueueConsumer.init(UndeploymentQueueConsumer.java:87)
at com.testcompany.app.fw.amt.rmq.UndeploymentQueueConsumer.handleDelivery(UndeploymentQueueConsumer.java:101)
at com.rabbitmq.client.impl.ConsumerDispatcher$5.run(ConsumerDispatcher.java:149)
at com.rabbitmq.client.impl.ConsumerWorkService$WorkPoolRunnable.run(ConsumerWorkService.java:104)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Constants Used
Constants.CONNECTION_URL = "jdbc:mariadb://%s:%s/";
HibernateConfig.java
#Configuration
#EnableTransactionManagement
public class HibernateConfig {
#Autowired
private DbProperties dbProperties;
#Bean
public LocalSessionFactoryBean hibernateSessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setAnnotatedPackages("com.testcompany.app.fw.amt.*");
sessionFactoryBean.setPackagesToScan("com.testcompany.app.fw.amt.*");
sessionFactoryBean.setHibernateProperties(additionalProperties());
return sessionFactoryBean;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(hibernateSessionFactory().getObject());
transactionManager.setDataSource(dataSource());
return transactionManager;
}
#Bean
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(String.format(AppConstants.CONNECTION_URL, dbProperties.getDbHost(), dbProperties.getDbPort()));
dataSource.setUsername(dbProperties.getDbUser());
dataSource.setPassword(dbProperties.getDbPassword());
dataSource.setMaximumPoolSize(30);
dataSource.setMinimumIdle(30);
dataSource.setConnectionTestQuery("SELECT 1");
return dataSource;
}
public Properties additionalProperties() {
Properties settings = new Properties();
settings.put(Environment.DIALECT, "org.hibernate.dialect.MariaDB53Dialect");
settings.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread");
return settings;
}
}
AppDeploymentHistoryServiceImpl.java
#Override
#Transactional
public void updateAllStatus(String clientDbName) throws ToolException {
try{
appDeploymentHistoryDao.updateAllStatus(clientDbName);
}catch(HibernateException he){
logger.error("***** <<< ERROR IN AppDeploymentHistoryServiceImpl.updateAllStatus >>> *****" , he);
}
}
AppDeploymentHistoryDaoImpl.java
#Override
public void updateAllStatus(String clientDbName) {
try {
Session session = sessionBuilder.getClientSession(clientDbName);
Query query = session.createSQLQuery("UPDATE `app_deployement_history` SET `is_current_exec` = 0 ");
query.executeUpdate();
} catch (Exception ex) {
logger.error("ERROR WHILE UPDATING APP DEPLOYMENT HISTORY STATUS { SET `is_current_exec` = 0 } IN DATABASE { AppDeploymentHistoryDaoImpl.updateAllStatus }" + ExceptionUtils.getFullStackTrace(ex));
}
}
SessionBuilderImpl.java
#Component
public class SessionBuilderImpl implements SessionBuilder {
private static final Logger LOGGER = LoggerFactory.getLogger(SessionBuilderImpl.class);
private static final String EXECPTION_MSG = "Error while exchanging database in session : Super amdin ";
#Autowired
private SessionFactory sessionFactory;
#Override
public Session getClientSession(String dbName) throws HibernateException {
Session currentSession = sessionFactory.getCurrentSession();
try {
Connection connection = sessionFactory.getSessionFactoryOptions().getServiceRegistry().
getService(ConnectionProvider.class).getConnection();
connection.setCatalog(dbName);
org.hibernate.SessionBuilder hibernateSessionBuilder = sessionFactory.withOptions();
currentSession = hibernateSessionBuilder.connection(connection).openSession();
} catch (SQLException ex) {
LOGGER.error("***** <<< HIBERNATE EXCEPTION : IN HIBERNATE_CONFIG : getSessionByDb(String dbName) >>> *****");
}
return currentSession;
}
#Override
public Connection getCurrentConnection() throws HibernateException {
Session currentSession = sessionFactory.getCurrentSession();
Connection connection = ((SessionImpl) currentSession).connection();
return connection;
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.testcompany.app.fw.amt</groupId>
<artifactId>AMTTool</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.22.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.20.Final</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1-rc1</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>test</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>javaxt</groupId>
<artifactId>javaxt-core</artifactId>
<version>1.7.8</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>maven-restlet</id>
<name>Public online Restlet repository</name>
<url>https://maven.restlet.talend.com/</url>
</repository>
<repository>
<id>jspresso-repository</id>
<url>http://repository.jspresso.org/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<name>AMTTool</name>
</project>
I highly doubt, the save and other cases are working here as well unless you have code other than posted here.
The problem with your code is that you are creating another session manually, the session bound with transaction manager(which spring is managing) is not aware of this, so your changes will not reflect.
Since, update/delete here is modifying native query, hibernate throwing error because it is not finding any transaction associated with it.
TL;DR
To verify it, I did little digging and created config same as you posted
#Configuration
#EnableConfigurationProperties(JpaProperties.class)
#EnableTransactionManagement
class CustomJpaConfiguration {
#Autowired
private JpaProperties jpaProperties;
#Bean
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(jpaProperties.getDatasource().getUrl());
dataSource.setDriverClassName(jpaProperties.getDatasource().getDriver());
dataSource.setUsername(jpaProperties.getDatasource().getUsername());
dataSource.setPassword(jpaProperties.getDatasource().getPassword());
dataSource.setConnectionTestQuery("select 1");
return dataSource;
}
#Bean
public LocalSessionFactoryBean localSessionFactoryBean() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan("com.example.jpa.model");
sessionFactory.setHibernateProperties(additionalProperties());
return sessionFactory;
}
private Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", jpaProperties.getDialect());
properties.setProperty("hibernate.show_sql", "" + jpaProperties.isShowSql());
properties.setProperty("hibernate.hbm2ddl.auto",
jpaProperties.getDdlMode() == null ? "none" : jpaProperties.getDdlMode());
return properties;
}
#Bean
public PlatformTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(localSessionFactoryBean().getObject());
transactionManager.setDataSource(dataSource());
return transactionManager;
}
}
First I checked with sessionFactory.getCurrentSession() if it gives the same error or not.
So, I created a small entity class
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String email;
#CreationTimestamp
#Column(name = "created_on", nullable = false, updatable = false)
private LocalDateTime createdOn;
#UpdateTimestamp
#Column(name = "updated_on", nullable = false)
private LocalDateTime updatedOn;
#Version
private int version;
#OneToMany(mappedBy = "user",fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
private final Set<Role> roles = new HashSet<>();
// Ignoring getters and setters
}
Then, I executed the insert case and found following logs1
2021-04-09 22:47:15.050 TRACE 63230 --- [ main] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.jdbc.datasource.ConnectionHolder#20163008] for key [HikariDataSource (HikariPool-1)] to thread [main]
2021-04-09 22:47:15.050 TRACE 63230 --- [ main] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.hibernate5.SessionHolder#3436d3d7] for key [org.hibernate.internal.SessionFactoryImpl#60ef30b1] to thread [main]
2021-04-09 22:47:15.050 TRACE 63230 --- [ main] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization
2021-04-09 22:47:15.050 TRACE 63230 --- [ main] o.s.t.i.TransactionInterceptor : Getting transaction for [com.example.jpa.service.UserService.addUser]
2021-04-09 22:47:15.058 TRACE 63230 --- [ main] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.hibernate5.SessionHolder#3436d3d7] for key [org.hibernate.internal.SessionFactoryImpl#60ef30b1] bound to thread [main]
Hibernate: insert into users (id, created_on, email, name, updated_on, version) values (null, ?, ?, ?, ?, ?)
2021-04-09 22:47:15.104 TRACE 63230 --- [ main] o.s.t.i.TransactionInterceptor : Completing transaction for [com.example.jpa.service.UserService.addUser]
2021-04-09 22:47:15.116 TRACE 63230 --- [ main] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2021-04-09 22:47:15.116 TRACE 63230 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.hibernate5.SessionHolder#3436d3d7] for key [org.hibernate.internal.SessionFactoryImpl#60ef30b1] from thread [main]
2021-04-09 22:47:15.116 TRACE 63230 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder#20163008] for key [HikariDataSource (HikariPool-1)] from thread [main]
You can see clearly see that insert statement executing and I did check the id returned, it was non-null.
Now, I used the session builder code you have posted and with that logs were
2021-04-09 22:45:42.300 TRACE 63184 --- [ main] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.jdbc.datasource.ConnectionHolder#60ef30b1] for key [HikariDataSource (HikariPool-1)] to thread [main]
2021-04-09 22:45:42.301 TRACE 63184 --- [ main] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.hibernate5.SessionHolder#3f40568e] for key [org.hibernate.internal.SessionFactoryImpl#3436d3d7] to thread [main]
2021-04-09 22:45:42.301 TRACE 63184 --- [ main] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization
2021-04-09 22:45:42.301 TRACE 63184 --- [ main] o.s.t.i.TransactionInterceptor : Getting transaction for [com.example.jpa.service.UserService.addUser]
2021-04-09 22:45:42.332 TRACE 63184 --- [ main] o.s.t.i.TransactionInterceptor : Completing transaction for [com.example.jpa.service.UserService.addUser]
2021-04-09 22:45:42.335 TRACE 63184 --- [ main] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2021-04-09 22:45:42.335 TRACE 63184 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.hibernate5.SessionHolder#3f40568e] for key [org.hibernate.internal.SessionFactoryImpl#3436d3d7] from thread [main]
2021-04-09 22:45:42.335 TRACE 63184 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder#60ef30b1] for key [HikariDataSource (HikariPool-1)] from thread [main]
Notice, in both logs the transaction synchronization manager starting and closing transaction but in former logs, it was issuing the insert statements and in later not, because you created the session again using Connection object, transaction manager never sees it.
Now, if I execute the delete case with first code, it works fine because transaction is known to the session but with your code session is different and that doesn't have any transaction associated, check below logs for both
2021-04-09 22:55:06.122 TRACE 63280 --- [ main] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.jdbc.datasource.ConnectionHolder#62d6ac] for key [HikariDataSource (HikariPool-1)] to thread [main]
2021-04-09 22:55:06.122 TRACE 63280 --- [ main] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.hibernate5.SessionHolder#103e9972] for key [org.hibernate.internal.SessionFactoryImpl#359ea595] to thread [main]
2021-04-09 22:55:06.122 TRACE 63280 --- [ main] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization
2021-04-09 22:55:06.122 TRACE 63280 --- [ main] o.s.t.i.TransactionInterceptor : Getting transaction for [com.example.jpa.service.UserService.deleteById]
2021-04-09 22:55:06.123 TRACE 63280 --- [ main] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.hibernate5.SessionHolder#103e9972] for key [org.hibernate.internal.SessionFactoryImpl#359ea595] bound to thread [main]
Hibernate: delete from users where id = 2
2021-04-09 22:55:06.169 TRACE 63280 --- [ main] o.s.t.i.TransactionInterceptor : Completing transaction for [com.example.jpa.service.UserService.deleteById]
2021-04-09 22:55:06.170 TRACE 63280 --- [ main] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2021-04-09 22:55:06.171 TRACE 63280 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.hibernate5.SessionHolder#103e9972] for key [org.hibernate.internal.SessionFactoryImpl#359ea595] from thread [main]
2021-04-09 22:55:06.171 TRACE 63280 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder#62d6ac] for key [HikariDataSource (HikariPool-1)] from thread [main]
And with your session builder code
2021-04-09 22:56:18.993 TRACE 63399 --- [ main] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.jdbc.datasource.ConnectionHolder#912747d] for key [HikariDataSource (HikariPool-1)] to thread [main]
2021-04-09 22:56:18.993 TRACE 63399 --- [ main] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.hibernate5.SessionHolder#78ea700f] for key [org.hibernate.internal.SessionFactoryImpl#4fef4f96] to thread [main]
2021-04-09 22:56:18.994 TRACE 63399 --- [ main] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization
2021-04-09 22:56:18.994 TRACE 63399 --- [ main] o.s.t.i.TransactionInterceptor : Getting transaction for [com.example.jpa.service.UserService.deleteById]
2021-04-09 22:56:19.028 TRACE 63399 --- [ main] o.s.t.i.TransactionInterceptor : Completing transaction for [com.example.jpa.service.UserService.deleteById] after exception: java.lang.IllegalStateException: javax.persistence.TransactionRequiredException: Executing an update/delete query
2021-04-09 22:56:19.029 TRACE 63399 --- [ main] o.s.t.i.RuleBasedTransactionAttribute : Applying rules to determine whether transaction should rollback on java.lang.IllegalStateException: javax.persistence.TransactionRequiredException: Executing an update/delete query
2021-04-09 22:56:19.029 TRACE 63399 --- [ main] o.s.t.i.RuleBasedTransactionAttribute : Winning rollback rule is: null
2021-04-09 22:56:19.029 TRACE 63399 --- [ main] o.s.t.i.RuleBasedTransactionAttribute : No relevant rollback rule found: applying default rules
2021-04-09 22:56:19.032 TRACE 63399 --- [ main] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2021-04-09 22:56:19.032 TRACE 63399 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.hibernate5.SessionHolder#78ea700f] for key [org.hibernate.internal.SessionFactoryImpl#4fef4f96] from thread [main]
2021-04-09 22:56:19.033 TRACE 63399 --- [ main] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder#912747d] for key [HikariDataSource (HikariPool-1)] from thread [main]
java.lang.IllegalStateException: javax.persistence.TransactionRequiredException: Executing an update/delete query
Conclusion
You would have to use the same session which is provided by the session factory, because spring's transaction flow only aware of that.
1 Logs are produced using 2 properties logging.level.org.springframework.transaction=trace and hibernate.show_sql=true

Unable to make actuator endpoints working in a legacy Spring boot project - getting authentication page

Spring boot actuator is already included in the POM, and it shows in the startup logs.
However, when I try to access /actuator or even the base url of my project, I get the following -
{
"timestamp": 1577096144986,
"status": 401,
"error": "Unauthorized",
"message": "Full authentication is required to access this resource",
"path": "/actuator"
}
I read that there could be basic HTTP authentication set for the end points.
I looked for spring.security.user.name, password in the config properties, but could not find any.
If I hit http://localhost:8083/actuator, or even http://localhost:8083/ or any URL other the mapped API end points, it seems, I get this password prompt on browser -
On application logs, I get this -
2019-12-23 19:30:54,489 75773 [XNIO-3 task-3] INFO c.c.common.web.LoggerInterceptor [LoggerInterceptor.java:42] - Visitor [okp91Dj1NzT2KPPUjaUvhqEg4oOhwPQ49I9LTR2z] [GET] [/error] [1ms] [OK]
2019-12-23 19:30:54,493 75777 [XNIO-3 task-3] ERROR org.apache.velocity [CommonsLogLogChute.java:96] - ResourceManager : unable to find resource 'error.vm' in any resource loader.
On entering credentials, it fails and the password prompt appears again, with the same logs as above repeated.
Updates
Spring boot version - 1.5.2.RELEASE.
There is a web.xml inside /src/main/resources. It has following -
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:META-INF/spring/applicationContext*.xml
classpath*:com.packagename
/WEB-INF/spring/oauth-security.xml
/WEB-INF/spring/security-config.xml
classpath*:META-INF/gateway/*.xml
</param-value>
</context-param>
I could locate the oauth-security.xml and security.xml files in this microservice component.
oauth-security.xml has oauth scopes based definitions for API paths -
<sec:http pattern="/service/v2/**"
create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager">
<sec:intercept-url pattern="/some/path/v2/profile/**" access="ROLE_USER,SCOPE_PROFILE" method="GET"/>
I see security-config.xml which imports webmvc-config.xml.
I see some of these in security-config.xml -
<sec:http pattern="/somepath/**">
<sec:intercept-url pattern="/somepath/**" access="ROLE_USER"/>
<sec:http-basic/>
</sec:http>
but I don't see any configurations for /** paths anywhere.
Update 2
I checked that there seem to be auth configurations in a file called customscopes.properties as well, which seems to be a custom file, added to webmvc-config.xml like this -
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:/spring/application.properties</value>
<value>classpath:/spring/local.properties</value>
<value>classpath:/spring/customscopes.properties</value>
<value> file:${project.config.dir}/application.properties </value>
<value>file:${project.config.dir}/customscopes.properties</value>
</list>
</property>
</bean>
customscopes.properties has urls like these -
service/v2/path/**=SCOPE_SOMETHING;
At the same, time, there is the same url in oauth-security.xml -
<sec:intercept-url pattern="/service/v2/path/**" access="SCOPE_SOMETHING"/>
I am not sure why there are two sets of configs. I tried changing those one by one, while keeping the other with authentication. I observed that only changing the customscopes.properties affected -
service/v2/path/**=IS_AUTHENTICATED_ANONYMOUSLY;
I am new to Spring Security as well. I checked this video tutorial but could not find those mentioned config methods in my project. There is no mention of WebSecurityConfigurerAdapter.
However, adding the path for actuator/** on both these files, with IS_AUTHENTICATED_ANONYMOUSLY did not work - 401 error as shown in the beginning.
Update 3
Oh, another thing - security-config.xml contains
<sec:http pattern="/favicon.ico" security="none"/>
And I see a difference in the logs when I access http://localhost:8083/actuator/ and http://localhost:8083/somethingelse/
http://localhost:8083/actuator/
Step 1 - Hit this url - log -
2019-12-24 12:31:03,051 590999 [XNIO-3 task-16] INFO c.c.common.web.LoggerInterceptor [LoggerInterceptor.java:42] - Visitor [OICBz6CqYzI58UqobnBYNEXsZUNErjBkv6wEUUkX] [GET] [/error] [2ms] [OK]
2019-12-24 12:31:03,054 591002 [XNIO-3 task-16] ERROR org.apache.velocity [CommonsLogLogChute.java:96] - ResourceManager : unable to find resource 'error.vm' in any resource loader.
Step 2 - cancel sign in form - get favicon.ico instead of /error -
2019-12-24 12:31:18,641 606589 [XNIO-3 task-20] ERROR org.apache.velocity [CommonsLogLogChute.java:96] - ResourceManager : unable to find resource 'error.vm' in any resource loader.
2019-12-24 12:31:18,912 606860 [XNIO-3 task-21] INFO c.c.common.web.LoggerInterceptor [LoggerInterceptor.java:42] - Visitor [OICBz6CqYzI58UqobnBYNEXsZUNErjBkv6wEUUkX] [GET] [/favicon.ico] [2ms] [OK]
http://localhost:8083/somethingelse
Step 1 - Hit this url - log -
2019-12-24 12:31:03,051 590999 [XNIO-3 task-16] INFO c.c.common.web.LoggerInterceptor [LoggerInterceptor.java:42] - Visitor [OICBz6CqYzI58UqobnBYNEXsZUNErjBkv6wEUUkX] [GET] [/error] [2ms] [OK]
2019-12-24 12:31:03,054 591002 [XNIO-3 task-16] ERROR org.apache.velocity [CommonsLogLogChute.java:96] - ResourceManager : unable to find resource 'error.vm' in any resource loader.
Step 2 - cancel sign in form - Same log as above, again
Update 4
If I add a class to extend WebSecurityConfigurerAdapter, and just add a permitAll() against my required paths -
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests().antMatchers("/service/trace/**").permitAll()
.antMatchers("/service/actuator/**").permitAll()
.antMatchers("/actuator/**").permitAll()
.antMatchers("/trace").permitAll()
.antMatchers("/actuator").permitAll();
}
I get different errors this time (404 Not found) -
{
"timestamp": 1577181851520,
"status": 404,
"error": "Not Found",
"message": "Not Found",
"path": "/service/trace"
}
Note - I have a doubt about which are the available actuator end points, so I am trying to ensure for all these combinations. See the application startup logs below if you can confirm on the basis of that.
I get 404 errors against all these URLs -
http://localhost:8083/service/actuator/beans
http://localhost:8083/actuator/beans
http://localhost:8083/beans
And my other authenticated API endpoints start giving this error -
{
"timestamp": 1577181062281,
"status": 403,
"error": "Forbidden",
"message": "Could not verify the provided CSRF token because your session was not found.",
"path": "/service/v2/some/end/point"
}
ALso, I found that we have these filters as well defined in the web.xml. So, it seems there is Spring configuration, as well as Spring boot addition. Correct me if my understanding is wrong.
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
So, the problem comes down to this -
I can't access the actuator end points. I see the following in application startup logs, containing actuator, but I can't seem to load them either. I guess Spring security is coming in between but not able to prevent the same.
2019-12-24 14:14:10,769 14209 [main] INFO o.s.b.a.e.m.EndpointHandlerMapping [AbstractHandlerMethodMapping.java:543] - Mapped "{[/beans || /beans.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-24 14:14:10,770 14210 [main] INFO o.s.b.a.e.m.EndpointHandlerMapping [AbstractHandlerMethodMapping.java:543] - Mapped "{[/health || /health.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(javax.servlet.http.HttpServletRequest,java.security.Principal)
2019-12-24 14:14:10,771 14211 [main] INFO o.s.b.a.e.m.EndpointHandlerMapping [AbstractHandlerMethodMapping.java:543] - Mapped "{[/autoconfig || /autoconfig.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-24 14:14:10,772 14212 [main] INFO o.s.b.a.e.m.EndpointHandlerMapping [AbstractHandlerMethodMapping.java:543] - Mapped "{[/metrics/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2019-12-24 14:14:10,772 14212 [main] INFO o.s.b.a.e.m.EndpointHandlerMapping [AbstractHandlerMethodMapping.java:543] - Mapped "{[/metrics || /metrics.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
Note -
I have added management.endpoints.web.exposure.include=* in application.properties
I can't see anything like this -
2019-12-24 15:57:41.245 INFO 37683 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 18 endpoint(s) beneath base path '/actuator'
spring-boot-starter-actuator-1.5.2.RELEASE.jar is there in External libraries of Intellij.
I have faced the similar error and added this configuration in application.properties :
management.endpoints.web.base-path=/
This would allow you to access all the actuator endpoints.
The error occurs as security is not enabled on the endpoint.
For a locally deployed app, add the following configuration to your application.properties file -
management.security.enabled=false
On a production app, more careful configurations would need to be made.
1)I tested the code with spring boot 1.5.2 and discovered that in this version the actuator endpoints are available in the root('/') path and not at /actuator path.
Your logs confirm it also:
2019-12-24 14:14:10,769 14209 [main] INFO o.s.b.a.e.m.EndpointHandlerMapping [AbstractHandlerMethodMapping.java:543] - Mapped "{[/beans || /beans.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
As you see in log, endpoint for example for beans is /beans. In your case http://localhost:8083/beans
In addition you need also as Prerak Jain wrote following:
management.security.enabled=false
2)
To your problem with HTTP 403:
{
"timestamp": 1577181062281,
"status": 403,
"error": "Forbidden",
"message": "Could not verify the provided CSRF token because your session was not found.",
"path": "/service/v2/some/end/point"
}
To fix it you need to add following to your configuration
"and().csrf().disable()", so for example:
http.authorizeRequests().antMatchers("/service/trace/**").permitAll().and().csrf().disable()
That disables csrf token stuff.
Dealing with Legacy application is never easy. Indeed, it seems like you are mixing Spring and Spring-boot configuration altogether. I suggest you to proces step by step. Go back to a working, stable state and then move on:
Make sure you are using the right dependencies
I've been doing some tests with spring-boot-starter-actuator with spring-boot-starter-parent.
Here is the content of my pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
Please notice that spring-boot-starter-actuator:2.2.2.RELEASE works in different ways that spring-boot-starter-actuator:1.5.2.RELEASE, mostly regarding the security.
Also note that we use the starterof every dependency. If not, you won't all spring boot autoconfiguration enabled.
Configure properly spring-boot-starter-actuator
In your application.properties, add the following lines :
# Make sure every actuator endpoints are located under the same root URL
management.context-path=/actuator
# Disable default actuator security rules to manage everything with your Java configuration
management.security.enabled=false
Try to manage only the access to /actuator
In your java configuration class, the one that extends WebSecurityConfigurerAdapter, apply the following changes:
#EnableWebSecurity // Enable spring security configuration
#Configuration // Is a Spring Configuration class
#Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER) // To override the default actuator security configuration
public class WebSecurity extends WebSecurityConfigurerAdapter {
/**
* We try to make sure you can easily manage spring actuator endpoints
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.mvcMatchers("/actuator/**").authenticated() // To restrict access to authenticated user on actuator endpoints
.anyRequest().permitAll()
.and()
.csrf().disable(); // If you want to POST data, you have to disable CSRF check. Otherwise, you always get an error when POSTing data on an unsecured URL.
}
}
For more information about CSRF, please check: https://fr.wikipedia.org/wiki/Cross-site_request_forgery
In the console, you're supposed to see something like this during the server start up:
019-12-30 12:13:34.767 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/beans || /actuator/beans.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-30 12:13:34.768 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/trace || /actuator/trace.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-30 12:13:34.769 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/configprops || /actuator/configprops.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-30 12:13:34.773 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/metrics/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2019-12-30 12:13:34.773 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/metrics || /actuator/metrics.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-30 12:13:34.774 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/autoconfig || /actuator/autoconfig.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-30 12:13:34.775 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/health || /actuator/health.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(javax.servlet.http.HttpServletRequest,java.security.Principal)
2019-12-30 12:13:34.776 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/dump || /actuator/dump.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-30 12:13:34.778 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/heapdump || /actuator/heapdump.json],methods=[GET],produces=[application/octet-stream]}" onto public void org.springframework.boot.actuate.endpoint.mvc.HeapdumpMvcEndpoint.invoke(boolean,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException,javax.servlet.ServletException
2019-12-30 12:13:34.779 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/mappings || /actuator/mappings.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-30 12:13:34.782 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/loggers/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.LoggersMvcEndpoint.get(java.lang.String)
2019-12-30 12:13:34.783 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/loggers/{name:.*}],methods=[POST],consumes=[application/vnd.spring-boot.actuator.v1+json || application/json],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.LoggersMvcEndpoint.set(java.lang.String,java.util.Map<java.lang.String, java.lang.String>)
2019-12-30 12:13:34.784 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/loggers || /actuator/loggers.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-30 12:13:34.785 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/auditevents || /actuator/auditevents.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public org.springframework.http.ResponseEntity<?> org.springframework.boot.actuate.endpoint.mvc.AuditEventsMvcEndpoint.findByPrincipalAndAfterAndType(java.lang.String,java.util.Date,java.lang.String)
2019-12-30 12:13:34.786 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/info || /actuator/info.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-12-30 12:13:34.788 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/env/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)
2019-12-30 12:13:34.789 INFO 13172 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/actuator/env || /actuator/env.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
Let me know if you have any difficulties, or you're console is printing different output.
Please also share your pom.xml if any of this works.
One way of running the actuator is assigning a different port to the actuator service
this could be done by adding following property to application.properties
management.server.port=8084
This way you can run and access actuator on a different port and can create rules on the gateway as to how it can be accessed.
Click here for detail
Another way is to disable security from actuator to add following property to the application.properties
management.endpoints.web.exposure.include=*
Click here for detail
Another way of bypassing all the security is following
#Configuration(proxyBeanMethods = false)
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
requests.anyRequest().permitAll());
}
}
Click here for detail
Hope it helps.

How to configure spring boot mvc app for JSP?

I am new to Spring boot ( and servlet 3.0 ). I am trying to create spring mvc project with JSP as view. When I return a view from my controller it is not getting resolved as JstlView.
Here is what I did:
#SpringBootApplication
public class MyApp extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
#Controller
public class MainController {
#RequestMapping( value="/main" , method = RequestMethod.GET )
public String main(){
return "main";
}
#RequestMapping( value="/" , method = RequestMethod.GET )
public String welcome(){
return "welcome";
}
}
Created both .jsp files in src\main\webapp\WEB-INF\jsp .
After googling I found that I need to specify this in application.properties So I added following in props:
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
logging.level.org.springframework: TRACE
logging.level.com: TRACE
Even after this it is not working. Here is the trace.
2016-04-24 19:54:49.016 TRACE 7880 --- [nio-8080-exec-1] .w.s.m.m.a.ServletInvocableHandlerMethod : Invoking [MainController.welcome] method with arguments []
2016-04-24 19:54:49.016 TRACE 7880 --- [nio-8080-exec-1] .w.s.m.m.a.ServletInvocableHandlerMethod : Method [welcome] returned [welcome]
2016-04-24 19:54:49.020 DEBUG 7880 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Requested media types are [text/html, application/xhtml+xml, image/webp, application/xml;q=0.9, */*;q=0.8] based on Accept header types and producible media types [*/*])
2016-04-24 19:54:49.020 DEBUG 7880 --- [nio-8080-exec-1] o.s.w.servlet.view.BeanNameViewResolver : No matching bean found for view name 'welcome'
2016-04-24 19:54:49.022 DEBUG 7880 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory : Invoking afterPropertiesSet() on bean with name 'welcome'
2016-04-24 19:54:49.022 TRACE 7880 --- [nio-8080-exec-1] o.s.w.s.v.InternalResourceViewResolver : Cached view [welcome]
2016-04-24 19:54:49.022 DEBUG 7880 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Returning [org.springframework.web.servlet.view.InternalResourceView: name 'welcome'; URL [/WEB-INF/jsp/welcome.jsp]] based on requested media type 'text/html'
2016-04-24 19:54:49.022 DEBUG 7880 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Rendering view [org.springframework.web.servlet.view.InternalResourceView: name 'welcome'; URL [/WEB-INF/jsp/welcome.jsp]] in DispatcherServlet with name 'dispatcherServlet'
2016-04-24 19:54:49.022 TRACE 7880 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView : Rendering view with name 'welcome' with model {} and static attributes {}
2016-04-24 19:54:49.026 DEBUG 7880 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView : Forwarding to resource [/WEB-INF/jsp/welcome.jsp] in InternalResourceView 'welcome'
2
As you see in the trace, this is trying to resolve /jsp/welcome.jsp as InternalResourceView instead of JstlView. Eventually it fails as 404.
What other steps I need to follow? Is there any tutorial for SpringBoot-mvc with jsp ?
P.S. I can create spring mvc app with jsp using web.xml ( using JstlView in my config file ). But I can't find any tutorial for Spring boot mvc with jsp.
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
also needed and your pages should be at /webapp/WEB-INF/jsp/
+
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
Assuming it is embedded Tomcat,
You need to have followings in your pom.xml
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
Embedded Tomcat core package has no JSP rendering support.
You do not require the ViewResolver. pom.xml needs the mentioned dependencies as told by Yura and place the jsp files in src\main\webapp\WEB-INF\jsp.
If we want to use jsp as view in spring boot(which by default has tomcat server) we need to add the following to our pom.xml:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
we need to add our pages inside
src/main/webapp/WEB-INF/view
After this we can specify the location for our jsp pages in application.properties
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
Create webapp/WEB-INF/views {Name the last folder as U Like }
under src/main
add jstl jar
add following two lines in application.properties
spring.mvc.view.prefix:/WEB-INF/views/
spring.mvc.view.suffix:.jsp
Run As Spring Boot App ..U are good to go !
For More U can consult my this project on github :
https://github.com/SudipBiswasRana/Using-JSP-As-View-For-Spring-Project

Categories