I have created a Java EE 6 restfull service and tried to integrate that with Spring Security. But, all the time I get different weird exceptions. Which doesn't make any sense or may be make sense but at least not for me.
Direction structure of my application is something like this:
com.security
UserDetailsSecurityConfig.java
com.service
ApplicationConfig.java
UserFacadeREST.java
com.config
AppConfig.java
My entities are auto generated so no error seems to be there. But, yes the three files seems fishy to me as UserFacadeREST is working fine when I don't integrate my application with Spring Security.
com.UserDetailsSecurityConfig.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class UserDetailsSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService( userDetailsService() );
}
#Override
protected void configure( HttpSecurity http ) throws Exception {
http
.httpBasic().and()
.sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS ).and()
.authorizeRequests().antMatchers("/**").hasRole( "USER" );
}
#Bean
public UserDetailsService userDetailsService() {
return new UserDetailsService() {
#Override
public UserDetails loadUserByUsername( final String username )
throws UsernameNotFoundException {
if( username.equals( "admin" ) ) {
return new User( username, "password", true, true, true, true,
Arrays.asList(
new SimpleGrantedAuthority("ROLE_USER" ),
new SimpleGrantedAuthority( "ROLE_ADMIN" )
)
);
} else if ( username.equals( "user" ) ) {
return new User( username, "password", true, true, true, true,
Arrays.asList(
new SimpleGrantedAuthority( "ROLE_USER" )
)
);
}
return null;
}
};
}
}
com.service.ApplicationConfig.java
#javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(com.service.UserFacadeREST.class);
}
}
com.service.UserFacadeREST.java
#Stateless
#Path("user")
public class UserFacadeREST extends AbstractFacade<UpUser> {
#PersistenceContext(unitName = "PU")
private EntityManager em;
public UserFacadeREST() {
super(User.class);
}
#POST
#Override
#Consumes({"application/xml", "application/json"})
public void create(User entity) {
super.create(entity);
}
#GET
#Path("count")
#Produces("text/plain")
public String countREST() {
return String.valueOf(super.count());
}
}
com.config.AppConfig.java
#Configuration
#Import( UserDetailsSecurityConfig.class )
public class AppConfig {
#Bean
public ApplicationConfig applicationConfig() {
return new ApplicationConfig();
}
#Bean
public UserFacadeREST userRestService() {
return new UserFacadeREST();
}
}
In whole code I have made few changes for hit and trial. And currently, I am getting an exception.
java.lang.IllegalStateException: No WebApplicationContext found: no
ContextLoaderListener registered?
Before that I was getting another exception which was
WebSecurityConfigurers must be unique. Order of 100 was already used
I am not getting what I am doing wrong in integrating Spring Security with Java EE 6. I am new to Spring so may be I am doing a blunder which seems obvious to me.
My web.xml file is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="rest-sec" version="3.0">
<display-name>rest</display-name>
<!-- Spring security -->
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<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>
<filter>
<filter-name>etagFilter</filter-name>
<filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>etagFilter</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
<!-- rest -->
<servlet>
<servlet-name>rest</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>com.labs.entities</param-value> <!-- won't find anything -->
</init-param>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<!-- Disables servlet container welcome file handling. Needed for compatibility
with Servlet 3.0 and Tomcat 7.0 -->
<welcome-file-list>
<welcome-file />
</welcome-file-list>
</web-app>
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
You need to tell the filter where to look for your context (it's default is to look in a place that is not used by the servlet you created). In your filter add an init param:
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
</init-param>
WebSecurityConfigurers must be unique. Order of 100 was already used
Do you have 2 beans of type WebSecurityConfigurerAdapter? Or is your UserDetailsSecurityConfig being loaded twice?
Related
i want to communicate 2 application , in my first application i'm using a restTemplate to send a notification to the second app , that's why i need to have a Rest endpoint inside my second App .
in the First App ( the one sending notification ) this is the method i use to send notification:
public void setSomething() {
String operation = "I'm sending you the operation ID";
// URL to the SelectSystem App
System.out.println("Tryin to send something to selectsystem-view");
final String uri = "http://localhost:8080/from";
RestTemplate restTemplate = new RestTemplate() ;
if (operation != null) {
restTemplate.postForObject( uri,operation, String.class);
System.out.println("Send is done !!");
}
}
In my second App (the one receiving)this is the class receiving the notification :
#RestController
public class NotificationReceiver {
#RequestMapping(value = "/from", method = RequestMethod.POST)
public ResponseEntity<String> createEmployee(#RequestBody String greeting) {
if (greeting !=null) {
System.out.println("The result From the other App is :"+greeting);
}
return new ResponseEntity(HttpStatus.CREATED);
}
#RequestMapping(value = "/from",method = RequestMethod.GET)
public void greeting() {
System.out.println("testing the restController");
}
}
the problem i'm having is that i can't map my RestController from the web.xml since i already have a JSF mapping , this is the jsf mapping web.xml :
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>modules/index.xhtml</welcome-file>
</welcome-file-list>
Any idea how to Map my RestController?
In my Spring Boot application with packaging type as war, i am configuring Spring MVC. As i understand we dont have to configure Dispatcher Servlet Manually. However, i old style of web.xml i used to configure Dispatcher Servlet and then i used to pass contextClass and contextConfigLocation as follows
<servlet>
<description>
</description>
<display-name>DispatcherServlet</display-name>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<description>contextClass</description>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<description>contextConfigLocation</description>
<param-name>contextConfigLocation</param-name>
<param-value>com.xxx.yyy.jdorderspringmvcweb.config.SpringMvcConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I belive this was to indicate that SpringMvcConfig (my custom class with spring mvc configuration) is the configuration class for Spring MVC..
However, In spring boot if Dispatcher Servlet is configured Automatically, how can i pass my custom class to dispatcher Servlet ?
In my Spring Boot application, my SpringMvcConfig class extends from WebMvcConfigurerAdapter and is annotated with #Configuration class
Help Needed...
Right in the configuration class which is annotated by #Configuration you could define your dispatcherServlet and pass init-parameter to it.
#Bean
public ServletRegistrationBean dispatcherServletRegistration() {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(dispatcherServlet());
registrationBean.addInitParameter("contextClass","org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
registrationBean.addInitParameter("contextConfigLocation","com.xxx.yyy.jdorderspringmvcweb.config.SpringMvcConfig");
return registrationBean;
}
Another way would be to create a paramter map and then set parameter for registration bean. This stream shows how to do it.
I think you have to create a config class as follow:
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MySpringMvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { DemoAppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
I'm using the Tuckey UrlRewriteFilter. I want to use a rewrite rule from a database, so using the <class-rule class="com.example.Foo" /> configuration, which lets you get rules at runtime. I created a class extending RewriteRule:
public class Foo extends RewriteRule {
#Autowired
private MyRepository myRepository;
public boolean init(ServletContext servletContext) {
return true;
}
#Override
public RewriteMatch matches(HttpServletRequest request, HttpServletResponse response) {
//myRepository is null
return super.matches(request, response);
}
#Override
public void destroy() {
}
}
I'd like to use a Spring Data JPA Repository inside this Foo class, but it looks the repository is null.
How can I inject it correctly?
Declare your filter in web.xml as usual, except that you will need to provide org.springframework.web.filter.DelegatingFilterProxy as the filter class name instead of your actual class name.
<filter>
<filter-name>urlRewriteFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>urlRewriteFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
Finally, in your ROOT application context, declare a bean pointing to your filter class and with the same name as the filter name provided in web.xml in the application context file loaded from web.xml:
<bean id="urlRewriteFilter" class="org.tuckey.web.filters.urlrewrite.UrlRewriteFilter"/>
Since your filter instance is now managed by Spring, you can inject any Spring managed bean into it.
I need to copy the contents of a web.xml to the WebAppInitializer.class (Java Configuration Class). I have copied the YahooFilter Class from web.xml (see code) but I am not sure how to add the init-params pragmatically.
I have pasted the web.xml and snippet of the Java Configuration class below. Can somebody take a look and provide some feedback?
<web-app>
<display-name>sample</display-Aname>
<filter>
<filter-name>YOSFilter</filter-name>
<filter-class>com.yahoo.yos.YahooFilter</filter-class>
<!--
optional param -
underlying oauth client class
possible values:
net.oauth.client.URLConnectionClient (default)
net.oauth.client.httpclient3.HttpClient3
net.oauth.client.httpclient4.HttpClient4
-->
<init-param>
<param-name>oauthConnectionClass</param-name>
<param-value>net.oauth.client.httpclient4.HttpClient4</param-value>
</init-param>
<!--
optional param -
redirect end-user if an access token is not found, set to false if you
are only making two-legged oauth calls e.g. oauth calls without an
access token to retrieve public information
defauts to true
-->
<init-param>
<param-name>redirect</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!--
The URL where the filter is mapped to will redirect the user to Yahoo for
authorization if an OAuth authorization token has not been obtained for the
user. Should correspond to your callback url
-->
<filter-mapping>
<filter-name>YOSFilter</filter-name>
<url-pattern>/login.jsp</url-pattern>
</filter-mapping>
</web-app>
Java Config Class
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
...
#Override
protected void registerDispatcherServlet(ServletContext servletContext) {
super.registerDispatcherServlet(servletContext);
servletContext.addListener(new HttpSessionEventPublisher());
// servletContext.addListener(new RequestContextListener());
}
#Override
protected Filter[] getServletFilters() {
DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy();
delegatingFilterProxy.setTargetBeanName("springSecurityFilterChain");
// FilterConfig filterConfig = delegatingFilterProxy.getFilterConfig();
YahooFilter yosFilter = new YahooFilter();
return new Filter[] {delegatingFilterProxy,yosFilter};
}
}
Try overriding onStartup() method and programatically register your filter with ServletContext like this:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
FilterRegistration yahooFilter = servletContext.addFilter("yahooFilter", new YahooFilter());
yahooFilter.setInitParameter("oauthConnectionClass", "net.oauth.client.httpclient4.HttpClient4");
yahooFilter.setInitParameter("redirect", "true");
}
I'm rather learning by doing so it might be a stupid question but I couldn't find any answer.
I have an JSF application which worked well as used with simple JDBC.
Take an example of the "domain.xhtml", which had a table listing elements from a "DomainController" bean. It was all working great then we switched to JPA. That controller has to use services so it's declared as #Component and includes (#Autowired) services from there. It also works well EXCEPT that all my JSF injections (#ManagedProperty) are not injected anymore, my #PostConstruct is not called anymore either.
Is there something I missed, or is wrong with that manner to proceed ?
#ManagedBean
#Component
public class DomainController implements Serializable {
private static Logger log = Logger.getLogger(DomainController.class);
private static final long serialVersionUID = -2862060884914941992L;
private List<Domain> allItems;
private Domain[] selectedItem;
private SelectItem[] yesNoNull;
private DomainFilter filter = new DomainFilter();
#Autowired
private DomainService domainService;
#Autowired
private ValidationLookUpService validationLookUpService;
#Autowired
private ValidationService validationService;
#ManagedProperty("#{workspace.on}")
private boolean wsOn;
// #ManagedProperty("#{libraryVersionController.selectedItem.id}")
// private Integer selectedLibVersionID;
#ManagedProperty("#{libraryVersionController.selectedItem}")
private LibraryVersion selectedLibVersion;
#ManagedProperty("#{obsoleteEntry}")
private PObsoleteEntry pObsoleteEntry;
#ManagedProperty("#{validationFailedItemsController}")
private ValidationFailedItemsController validationFailedCont;
private Domain itemEdited;
private boolean persisted = false;
public DomainController() {
log.info("Creating metadata controller");
allItems = new ArrayList<Domain>();
// model for a yes/no/null column filtering
yesNoNull = new SelectItem[4];
yesNoNull[0] = new SelectItem("", "All");
yesNoNull[1] = new SelectItem("true", "yes");
yesNoNull[2] = new SelectItem("false", "no");
yesNoNull[3] = new SelectItem("null", "not yet validated");
}
#PostConstruct
public void test()
{
log.info("!!!");
log.info("WS is ... "+wsOn);
// NOT CALLED ANYMORE
}
...
My web.xml :
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets
and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name> <!-- indique le fichier de configuration pour Spring -->
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>true</param-value>
</context-param>
<context-param> <!-- to really skip comments in xhtml pages -->
<param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/app/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/spring/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<listener> <!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener> <!-- links JSF with spring -->
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener> <!-- parses JSF configuration -->
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<listener> <!-- vide le cache d’introspection Spring à l’arrêt du serveur. Ce listener n’est pas obligatoire mais conseillé -->
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
</web-app>
Thanks !
Correct me if I'm wrong but I don't see how I could just choose one, as Spring manages the back-end and JSF(+primefaces) the front-end.
I thought that the controller "could" have been the interface between the two, that's why I naively mixed them.
After some testing around your comments, I made my controller only use JSF and it injects the services using #ManagedBean (I didn't know either that using #ManagedBean it could inject a #Service Spring-managed bean) so that answers my question :)
Below is the corrected code working.
Thanks also for redirecting me in the right direction !
Controller
/**
* This is the controller for a Domain
*
*/
#ManagedBean
public class DomainController implements Serializable {
private static Logger log = Logger.getLogger(DomainController.class);
private static final long serialVersionUID = -2862060884914941992L;
private List<Domain> allItems;
private Domain[] selectedItem;
private SelectItem[] yesNoNull;
private DomainFilter filter = new DomainFilter();
#ManagedProperty(value="#{domainService}")
private DomainService domainService;
#ManagedProperty("#{workspace.on}")
private boolean wsOn;
#ManagedProperty("#{libraryVersionController.selectedItem}")
private LibraryVersion selectedLibVersion;
private Domain itemEdited;
private boolean persisted = false;
/**
* creates a list populated from the database
*/
public DomainController() {
log.info("Creating metadata controller");
allItems = new ArrayList<Domain>();
// model for a yes/no/null column filtering
yesNoNull = new SelectItem[4];
yesNoNull[0] = new SelectItem("", "All");
yesNoNull[1] = new SelectItem("true", "yes");
yesNoNull[2] = new SelectItem("false", "no");
yesNoNull[3] = new SelectItem("null", "not yet validated");
}
#PostConstruct
public void test()
{
Domain d = new Domain();
d.setDataset("will it work ?"); // yes
try {
domainService.saveOrUpdate(d);
} catch (DataModelConsistencyException e) {
e.printStackTrace();
}
}
// all functions
public DomainService getDomainService() {
return domainService;
}
public void setDomainService(DomainService domainService) {
this.domainService = domainService;
}
}
Service
public interface DomainService extends IVersionedServiceBase<Domain> {
public Domain saveOrUpdate(Domain d) throws DataModelConsistencyException;
public Domain getRelatedVariables(Domain d, VersionedObjectFilter versionedObjectFilter) throws DataModelConsistencyException;
StringAndError getVarNameAndKeyOrderForDomain(Domain d, VersionedObjectFilter versionedObjectFilter) throws DataModelConsistencyException;
}
Implementation of service
#Service("domainService")
#Transactional(readOnly = true)
public class DomainServiceImpl extends VersionedServiceBase<Domain> implements DomainService {
/**
* Private logger for this class
*/
#SuppressWarnings("unused")
private static final Logger log = Logger.getLogger(DomainServiceImpl.class.getName());
#Autowired
private DomainDao domainDao;
#Autowired
private VariableDao variableDao;
#Autowired
private DomainPurposeDao domainPurposeDao;
#Autowired
private DomainClassDao domainClassDao;
etc.