Keycloak with spring boot issue when deploying on tomcat - java

I have secured my a Spring application with KeyCloak using Spring Security Adapter, this works fine on my local machine, but when i deployed the WAR on tomcat and try to call the API, i get the following internal server error :
o.s.b.w.servlet.support.ErrorPageFilter : Forwarding to error page from request [/api/statutOperations]
due to exception [null]
java.lang.NullPointerException: null
at org.keycloak.adapters.KeycloakDeploymentBuilder.internalBuild(KeycloakDeploymentBuilder.java:57) ~[keycloak-adapter-core-10.0.2.jar:10.0.2]
at org.keycloak.adapters.KeycloakDeploymentBuilder.build(KeycloakDeploymentBuilder.java:202) ~[keycloak-adapter-core-10.0.2.jar:10.0.2]
at org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver.resolve(KeycloakSpringBootConfigResolver.java:39) ~[keycloak-spr
Did i miss something, or is my configuration wrong, below is the necessary config :
Keycloak Config :
#Configuration
public class KeycloakConfig {
#Bean
KeycloakSpringBootConfigResolver configResolver() {
return new KeycloakSpringBootConfigResolver();
}
#Bean
KeycloakRestTemplate keycloakRestTemplate(KeycloakClientRequestFactory keycloakClientRequestFactory) {
return new KeycloakRestTemplate(keycloakClientRequestFactory);
}
}
#KeycloakConfiguration
public class KeycloakSpringSecuriteConfig extends KeycloakWebSecurityConfigurerAdapter {
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http); http.authorizeRequests().antMatchers("/api/**").authenticated().anyRequest().permitAll();
}
}
application.properties :
keycloak.realm=cirta
keycloak.auth-server-url=http://localhost:8085/auth
keycloak.resource=cirta-api
keycloak.public-client=true
keycloak.cors=true
keycloak.ssl-required=external
I also added the following context.xml keycloak.json and web.xml in META-INF and WEB-INF directories :
context.xml
<Context path="/cirtaapi">
<Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
</Context>
keycloak.json
{
"realm" : "cirta",
"resource" : "cirta-api",
"auth-server-url" : "https://localhost:8085/auth",
"ssl-required" : "external",
"enable-cors" : true
}
web.xml
<module-name>cirtaapi</module-name>
<security-constraint>
<web-resource-collection>
<web-resource-name>Operations</web-resource-name>
<url-pattern>/api/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>app-manager</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>KEYCLOAK</auth-method>
<realm-name>cirta</realm-name>
</login-config>
<security-role>
<role-name>app-manager</role-name>
</security-role>

This has been fixed in keycloak 11.0.0. Similar question is out there to describe this: NPE when loading custom SecurityConfig for Keycloak in WebMvcTest and provide a workaround for version 9.0.1 to 10.
See also: https://github.com/gtiwari333/spring-boot-web-application-seed/blob/master/main-app/src/main/java/gt/app/config/security/SecurityConfig.java

Related

session timeout in spring boot + React

I am able to configure session timeout in web.xml, but after session timeout getting errors from react side.
using spring security and jwt token.
WebSecurity.java
#Configuration
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailServiceImpl userDetails;
#Autowired
JWTAuthenticationFilter jwtRequestFilter;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetails).passwordEncoder(getPasswordEncoder());
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.GET, "/index*", "/static/**", "/*.js", "/*.json", "/*.ico", "/*.png")
.permitAll().antMatchers("/resources/**", "/login", "/", "/actuator").permitAll()
.antMatchers("/authenticate/**", "/identity/**").permitAll().anyRequest().authenticated().and().cors().and()
.exceptionHandling().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
web.xml
<session-config>
<session-timeout>1</session-timeout>
</session-config>
I tried sessionManagement().InvalidSessionURL("url") but on login it always redirect to invalid url only.
There is no api for login, we are loading from React directly.
Please let me know how to redirect to login page on session timeout ? and how to handle errors from react side ?

How to enable the existing spring security for a given Servlet?

I have a servlet deployed
Myservlet.java
#Configurable
public class MyServlet extends HttpServlet {
#Autowired
MyService service;
#Override
public void init(ServletConfig config) throws javax.servlet.ServletException{
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) {
//Do something here
}
Now the security for this is enabled in web.xml as :
<security-constraint>
<web-resource-collection>
<web-resource-name>myServlet</web-resource-name>
<url-pattern>/myUrl/*</url-pattern>
<http-method>HEAD</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>user</role-name>
</security-role>
But where this spring application deployed already has a spring security enabled via #EnableWebSecurity
The controllers deployed in the spring application are all correctly getting authenticated as expected. But the servlet is not authenticating with spring security. I believe what's mentioned in the is stopping it from authenticating.
How do i make the servlet work with Spring security ?
Edit 1:
Spring security configuration: (Note that this is not syntactically correct) but user/role and datasource are all correct in my code. It's working fine for other REST apis deployed in spring application
#Configuration
#EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
String user_query = "select user from userTable where id=9999";
String role_query = "select role from roleTable where id=6666";
logger.info("Using the following query for role : " + role_query);
auth.
jdbcAuthentication()
.dataSource(dataSource) //Datasource is injected to this class
.usersByUsernameQuery(user_query)
.passwordEncoder(passwordEncoder())
.authoritiesByUsernameQuery(role_query);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().hasRole("myrole")
.and()
.httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(runAsAuthenticationProvider());
}
#Autowired
protected RunAsManager runAsManager() {
RunAsManagerImpl runAsManager = new RunAsManagerImpl();
runAsManager.setKey("MyRunAsKey");
return runAsManager;
}

how to use guice correctly for dependency inject in java servlets?

sorry for the bad question title...
Disclaimer: Not much experience around web-apps, primarily used dropwizard.
So i have been trying to use guice in my java web-app
Initially without guice, servlets were serving the api correctly but after configuring servlet to be served from guice for below endpoint,
http://localhost:8080/myServlets/test
I am getting below error:
HTTP Status 404 – Not Found Type Status Report
Message The requested resource [/myServlets/test] is not available
Description The origin server did not find a current representation
for the target resource or is not willing to disclose that one exists.
Apache Tomcat/8.5.57
with below stacktrace:
16-Sep-2020 11:33:43.941 INFO [AsyncFileHandlerWriter-2008362258] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [com.google.inject.internal.util.LineNumbers$LineNumberReader]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [com.google.inject.internal.util.LineNumbers$LineNumberReader]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1378)
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1366)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1218)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1180)
at com.google.inject.internal.util.StackTraceElements$1.load(StackTraceElements.java:49)
at com.google.inject.internal.util.StackTraceElements$1.load(StackTraceElements.java:45)
at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3529)
at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2278)
at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2155)
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2045)
at com.google.common.cache.LocalCache.get(LocalCache.java:3953)
at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3976)
at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4960)
at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4966)
at com.google.inject.internal.util.StackTraceElements.forMember(StackTraceElements.java:71)
at com.google.inject.internal.Messages.formatParameter(Messages.java:286)
at com.google.inject.internal.Messages.formatInjectionPoint(Messages.java:273)
at com.google.inject.internal.Messages.formatSource(Messages.java:229)
at com.google.inject.internal.Messages.formatSource(Messages.java:220)
at com.google.inject.internal.Messages.formatMessages(Messages.java:90)
at com.google.inject.ConfigurationException.getMessage(ConfigurationException.java:73)
at java.base/java.lang.Throwable.getLocalizedMessage(Throwable.java:396)
at java.base/java.lang.Throwable.toString(Throwable.java:485)
at java.base/java.lang.String.valueOf(String.java:2951)
at java.base/java.io.PrintWriter.println(PrintWriter.java:837)
at org.apache.juli.OneLineFormatter$IndentingPrintWriter.println(OneLineFormatter.java:298)
at java.base/java.lang.Throwable$WrappedPrintWriter.println(Throwable.java:768)
at java.base/java.lang.Throwable.printStackTrace(Throwable.java:659)
at java.base/java.lang.Throwable.printStackTrace(Throwable.java:725)
at org.apache.juli.OneLineFormatter.format(OneLineFormatter.java:171)
at org.apache.juli.FileHandler.publish(FileHandler.java:291)
at org.apache.juli.AsyncFileHandler.publishInternal(AsyncFileHandler.java:146)
at org.apache.juli.AsyncFileHandler$LogEntry.flush(AsyncFileHandler.java:185)
at org.apache.juli.AsyncFileHandler$LoggerThread.run(AsyncFileHandler.java:161)
Tried Guice Git but createInjector part stumps me as there is no main method.
Reference code is below, any help is appreciated!
CacheService
public interface CacheService {
public abstract String hello();
}
CacheServiceImpl
import com.google.inject.Provides;
public class CacheServiceImpl implements CacheService {
#Provides
public String hello() {
return "hello world";
}
}
CacheModule
import com.google.inject.AbstractModule;
public class CacheModule extends AbstractModule {
protected void configure() {
bind(CacheService.class).to(CacheServiceImpl.class);
}
}
MyGuiceServletConfig
public class MyGuiceServletConfig extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
return Guice.createInjector(new ServletModule() {
#Override
protected void configureServlets() {
serve("/*").with(ResourceServlet.class);
bind(CacheModule.class);
}
});
}
}
ResourceServlet
#Slf4j
#Path("/")
#Singleton
public class ResourceServlet extends HttpServlet {
#Context
private ServletContext servletContext;
#Inject
public ResourceServlet(CacheService storageModule) throws JAXBException {
log.info("base {}", storageModule.hello());
}
#GET
#Path("/test")
#Produces({MediaType.APPLICATION_JSON})
public Product abc() {
log.info("servletContext {}", servletContext);
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>myServlets</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- Inject Guice -->
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.myorg.application.guice.MyGuiceServletConfig</listener-class>
</listener>
</web-app>

Implement a custom ServerAuthModule for JBoss

I need to remember the original URL of the Http Request, then redirect this request to a web form for a user authentication. In case of a successful authentication, the user must be redirected to the original URL just remembered above.
I am using JBoss 7.1.1 Final, a standard web.xml, and the JBoss Login Module org.jboss.security.auth.spi.DatabaseServerLoginModule:
I had referred the following links which didn't answer my question completely:
Precedence of security-constraint over filters in
Servlets
Jaspic ServerAuthModule delegating to JAAS Krb5LoginModule
Implementing container authentication in Java EE with JASPIC
Oracle GlassFish Server 3.0.1 Application Development Guide
However, after impltementing my solution, my custom ServerAuthModule is not called at all. What is even worse, I did not get any HttpResponse from the server. Something got broken, please help!
My web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>All resources in /pages/*</web-resource-name>
<description>All resources in /pages/*</description>
<url-pattern>/pages/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>general</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<display-name>Restrict direct access to the /resources folder.</display-name>
<web-resource-collection>
<web-resource-name>The /resources folder.</web-resource-name>
<url-pattern>/resources/*</url-pattern>
</web-resource-collection>
<auth-constraint />
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsf</form-login-page>
<form-error-page>/loginFailed.jsf</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>general</role-name>
</security-role>
My jboss-web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<security-domain>jBossJaasMysqlRealm</security-domain>
<valve>
<class-name>org.jboss.as.web.security.jaspi.WebJASPIAuthenticator</class-name>
</valve>
</jboss-web>
My standalone.xml:
<security-domain name="jBossJaasMysqlRealm" cache-type="default">
<authentication-jaspi>
<login-module-stack name="lm-stack">
<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
<module-option name="dsJndiName" value="java:/MySqlDS_IamOK"/>
<module-option name="principalsQuery" value="select password from user where username=?"/>
<module-option name="rolesQuery" value="select role, 'Roles' from user_role where username=?"/>
</login-module>
</login-module-stack>
<auth-module code="at.alex.ok.web.utils.RequestMarkerServerAuthModule" login-module-stack-ref="lm-stack"/>
</authentication-jaspi>
</security-domain>
My custom WebServerAuthModule:
import org.jboss.as.web.security.jaspi.modules.WebServerAuthModule;
public class RequestMarkerServerAuthModule extends WebServerAuthModule {
public static final String ORIGINAL_URL = "originalURL";
protected static final Class[] supportedMessageTypes = new Class[] {
HttpServletRequest.class, HttpServletResponse.class };
public void initialize(MessagePolicy reqPolicy, MessagePolicy resPolicy,
CallbackHandler cBH, Map opts) throws AuthException {
System.out.println( this.getClass().getName() + ".initialize() called");
}
public Class[] getSupportedMessageTypes() {
return supportedMessageTypes;
}
public AuthStatus validateRequest(MessageInfo msgInfo, Subject client,
Subject server) throws AuthException {
try {
System.out.println( this.getClass().getName() + ".validateRequest() called");
processAuthorizationToken(msgInfo, client);
return AuthStatus.SUCCESS;
} catch (Exception e) {
AuthException ae = new AuthException();
ae.initCause(e);
throw ae;
}
}
private void processAuthorizationToken(MessageInfo msgInfo, Subject s)
throws AuthException {
HttpServletRequest request = (HttpServletRequest) msgInfo
.getRequestMessage();
String originalURL = request.getRequestURL().toString();
request.getSession().setAttribute(ORIGINAL_URL, originalURL);
}
public AuthStatus secureResponse(MessageInfo msgInfo, Subject service)
throws AuthException {
System.out.println( this.getClass().getName() + ".secureResponse() called");
return AuthStatus.SEND_SUCCESS;
}
public void cleanSubject(MessageInfo msgInfo, Subject subject)
throws AuthException {
System.out.println( this.getClass().getName() + ".cleanSubject() called");
}
}
This question is put incorectly, because:
For a redirect to the originally requested URL after a successfull login, there is no need to implement a custom ServerAuthModule for JBoss.
The interface javax.servlet.RequestDispatcher has the constant FORWARD_REQUEST_URI, which denotes the name of the Http-Request attribute under which the original request URI is made available to the processor of the forwarded request.
Using JSF 2.2 and a View-Scoped backing bean LoginBean, my solution is simply to obtain the originally requested URL in a #PostConstruct method of the backing bean, and store it in a session attribute, as follows:
#ManagedBean(name="loginBean")
#ViewScoped
public class LoginBean {
private String originalURL;
#PostConstruct
private void init() {
ExternalContext extCtx = FacesContext.getCurrentInstance().getExternalContext();
String origURL = (String) extCtx.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
HttpServletRequest request = (HttpServletRequest) extCtx.getRequest();
HttpSession session = (HttpSession)extCtx.getSession(false);
if (session == null){
session = (HttpSession)extCtx.getSession(true);
}
if (origURL!=null && session.getAttribute(ORIGINAL_URL) == null){
String applicationName = request.getContextPath();
origURL = origURL.substring(applicationName.length(), origURL.length());
session.setAttribute(ORIGINAL_URL, origURL);
}
}
Then, in the login() method of the same backing bean, redirect the user to the originally requested URL in case of a successfull log-in like this:
public String login() {
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
try {
request.login(this.getLogin(), this.getPassword());
} catch (ServletException e) {
// handle bad username / password here
}
return this.originalURL + "?faces-redirect=true";
}

Why did my project need a applicationContext.xml for Spring Security with JavaConfig

I had a Spring MVC project that was using XML for all the config stuff but I remove all the XML and made them into JavaConfig (Everything but Spring Security). Once I try to get Spring Security working I could see that my project was blowing up looking for applicationContext.xml in WEB.INF. I dont have anything pointing to that so who do I need it>?
my secuirty.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<global-method-security pre-post-annotations="enabled" />
<http use-expressions="true">
<intercept-url access="hasRole('ROLE_VERIFIED_MEMBER')" pattern="/mrequest**" />
<intercept-url pattern='/*' access='permitAll' />
<form-login default-target-url="/visit" />
<logout logout-success-url="/" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="cpilling04#aol.com.dev" password="testing" authorities="ROLE_VERIFIED_MEMBER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Here is my webconfig:
#Configuration
#EnableWebMvc
#Import(DatabaseConfig.class)
#ImportResource("/WEB-INF/spring/secuirty.xml")
public class WebMVCConfig extends WebMvcConfigurerAdapter {
private static final String MESSAGE_SOURCE = "/WEB-INF/classes/messages";
private static final Logger logger = LoggerFactory.getLogger(WebMVCConfig.class);
#Bean
public ViewResolver resolver() {
UrlBasedViewResolver url = new UrlBasedViewResolver();
url.setPrefix("/WEB-INF/view/");
url.setViewClass(JstlView.class);
url.setSuffix(".jsp");
return url;
}
#Bean(name = "messageSource")
public MessageSource configureMessageSource() {
logger.debug("setting up message source");
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename(MESSAGE_SOURCE);
messageSource.setCacheSeconds(5);
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver lr = new SessionLocaleResolver();
lr.setDefaultLocale(Locale.ENGLISH);
return lr;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
logger.debug("setting up resource handlers");
registry.addResourceHandler("/resources/").addResourceLocations("/resources/**");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
logger.debug("configureDefaultServletHandling");
configurer.enable();
}
#Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor());
}
#Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
SimpleMappingExceptionResolver b = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.put("org.springframework.web.servlet.PageNotFound", "p404");
mappings.put("org.springframework.dao.DataAccessException", "dataAccessFailure");
mappings.put("org.springframework.transaction.TransactionException", "dataAccessFailure");
b.setExceptionMappings(mappings);
return b;
}
#Bean
public RequestTrackerConfig requestTrackerConfig()
{
RequestTrackerConfig tr = new RequestTrackerConfig();
tr.setPassword("Waiting#$");
tr.setUrl("https://uftwfrt01-dev.uftmasterad.org/REST/1.0");
tr.setUser("root");
return tr;
}
}
Here is my DatabaseConfig:
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages= "org.uftwf")
#PropertySource(value = "classpath:application.properties")
public class DatabaseConfig {
private static final Logger logger = LoggerFactory.getLogger(DatabaseConfig.class);
#Value("${jdbc.driverClassName}")
private String driverClassName;
#Value("${jdbc.url}")
private String url;
#Value("${jdbc.username}")
private String username;
#Value("${jdbc.password}")
private String password;
#Value("${hibernate.dialect}")
private String hibernateDialect;
#Value("${hibernate.show_sql}")
private String hibernateShowSql;
#Value("${hibernate.hbm2ddl.auto}")
private String hibernateHbm2ddlAuto;
#Bean
public PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer()
{
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setLocation(new ClassPathResource("application.properties"));
ppc.setIgnoreUnresolvablePlaceholders(true);
return ppc;
}
#Bean
public DataSource dataSource() {
try {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:jboss/datasources/mySQLDB");
}
catch (Exception e)
{
}
return null;
}
#Bean
public SessionFactory sessionFactory()
{
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setHibernateProperties(getHibernateProperties());
factoryBean.setPackagesToScan("org.uftwf.inquiry.model");
try {
factoryBean.afterPropertiesSet();
} catch (IOException e) {
logger.error(e.getMessage());
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
return factoryBean.getObject();
}
#Bean
public Properties getHibernateProperties()
{
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
hibernateProperties.setProperty("hibernate.show_sql", "true");
hibernateProperties.setProperty("hibernate.format_sql", "true");
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update");
hibernateProperties.setProperty("javax.persistence.validation.mode", "none");
//Audit History flags
hibernateProperties.setProperty("org.hibernate.envers.store_data_at_delete", "true");
hibernateProperties.setProperty("org.hibernate.envers.global_with_modified_flag", "true");
return hibernateProperties;
}
#Bean
public HibernateTransactionManager hibernateTransactionManager()
{
HibernateTransactionManager htm = new HibernateTransactionManager();
htm.setSessionFactory(sessionFactory());
htm.afterPropertiesSet();
return htm;
}
}
and my web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>Inquiry</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.uftwf.inquiry.config, org.uftwf.inquiry.controller</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--
<security-constraint>
<web-resource-collection>
<web-resource-name>securedapp</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
-->
</web-app>
So I dont see anything looking for applicationContext.xml .... can someone please tell me why I need it to add it and once I did it started to work
Spring Application contexts are hierarchical. The typical arrangement in a web app is that the context loader listener bootstraps your AC and makes them available 'globally', then each individual DispatcherServlet will have its own child application context that can 'see' all the beans (typically services, data sources, etc.) from the context loader listener's AC. In all cases - when specifying the ContextLoaderListener or the DispatcherServlet - Spring will automatically (based on convention) look for an XML application context and attempt to load it. Usually you can disable this by simply specifying an empty contextConfigLocation param ("") or by telling it that it should expect a Java config class, instead (contextClass attribute). BTW, it is possible to have multiple DispatcherServlets. You might, for example, use Spring Integration's inbound HTTP adapter with one, a Spring Web Services endpoint with another, Spring MVC app on another and a Spring HTTP invoker endpoint on another still, and they'd all be exposed via a DispatcherServlet. You could, theoretically, make them all work in the same DispatcherServlet, but the isolation helps keep things less cluttered and they can all share the same single instances of global, more expensive beans, like DataSources.
You configured ContextLoaderListener in your web.xml, but haven't specified the contextConfigLocation context-param. The behaviour in this case is described by the javadoc of that class:
Processes a "contextConfigLocation" context-param [...] If not explicitly specified, the context implementation is supposed to use a default location (with XmlWebApplicationContext: "/WEB-INF/applicationContext.xml").
So, it is the ContextLoaderListener that requires a applicationContext.xml.
To make sure your app doesn't use applicationContext.xml you can do something similar to this. You can see how this all goes together here.
public class MyInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) {
//Clear out reference to applicationContext.xml
servletContext.setInitParameter("contextConfigLocation", "");
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(MySpringRootConfiguration.class);
// Manage the lifecycle of the root application context
servletContext.addListener(new ContextLoaderListener(rootContext));
//Add jersey or any other servlets
ServletContainer jerseyServlet = new ServletContainer(new RestApplication());
Dynamic servlet = servletContext.addServlet("jersey-servlet", jerseyServlet);
servlet.addMapping("/api/*");
servlet.setLoadOnStartup(1);
}
}

Categories

Resources