diff --git a/libresonic-main/src/main/java/org/libresonic/player/boot/Application.java b/libresonic-main/src/main/java/org/libresonic/player/boot/Application.java
index e9caf628..dfb807f6 100644
--- a/libresonic-main/src/main/java/org/libresonic/player/boot/Application.java
+++ b/libresonic-main/src/main/java/org/libresonic/player/boot/Application.java
@@ -1,12 +1,9 @@
package org.libresonic.player.boot;
import org.directwebremoting.servlet.DwrServlet;
-import org.libresonic.player.filter.RESTFilter;
-import org.libresonic.player.security.RESTRequestParameterProcessingFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
@@ -18,7 +15,6 @@ import org.springframework.context.annotation.ImportResource;
@ImportResource(value = {"classpath:/applicationContext-service.xml",
"classpath:/applicationContext-cache.xml",
"classpath:/applicationContext-sonos.xml",
- "classpath:/applicationContext-security.xml",
"classpath:/libresonic-servlet.xml"})
public class Application extends SpringBootServletInitializer {
@@ -34,21 +30,6 @@ public class Application extends SpringBootServletInitializer {
return servlet;
}
- /**
- * Registers the rest servlet filter.
- *
- * @return a registration bean.
- */
- @Bean
- public FilterRegistrationBean restFilterRegistration() {
- FilterRegistrationBean registration = new FilterRegistrationBean();
- registration.setFilter(new RESTFilter());
- registration.addUrlPatterns("/rest/*");
- registration.setName("RESTFilter");
- return registration;
- }
-
-
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
diff --git a/libresonic-main/src/main/java/org/libresonic/player/security/LoginFailureLogger.java b/libresonic-main/src/main/java/org/libresonic/player/security/LoginFailureLogger.java
index 0e7b056e..2fce8bcd 100644
--- a/libresonic-main/src/main/java/org/libresonic/player/security/LoginFailureLogger.java
+++ b/libresonic-main/src/main/java/org/libresonic/player/security/LoginFailureLogger.java
@@ -20,6 +20,7 @@
package org.libresonic.player.security;
import org.libresonic.player.Logger;
+import org.springframework.stereotype.Component;
/**
* Logs login failures. Can be used by tools like fail2ban for blocking IP addresses.
@@ -27,6 +28,7 @@ import org.libresonic.player.Logger;
* @author Sindre Mehus
* @version $Id$
*/
+@Component
public class LoginFailureLogger {
private static final Logger LOG = Logger.getLogger(LoginFailureLogger.class);
diff --git a/libresonic-main/src/main/java/org/libresonic/player/security/RESTRequestParameterProcessingFilter.java b/libresonic-main/src/main/java/org/libresonic/player/security/RESTRequestParameterProcessingFilter.java
index dd974919..5e99b1f5 100644
--- a/libresonic-main/src/main/java/org/libresonic/player/security/RESTRequestParameterProcessingFilter.java
+++ b/libresonic-main/src/main/java/org/libresonic/player/security/RESTRequestParameterProcessingFilter.java
@@ -27,15 +27,14 @@ import org.libresonic.player.controller.RESTController;
import org.libresonic.player.domain.User;
import org.libresonic.player.domain.Version;
import org.libresonic.player.service.SecurityService;
-import org.libresonic.player.service.SettingsService;
import org.libresonic.player.util.StringUtil;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.authentication.ProviderManager;
+import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.stereotype.Component;
+import org.springframework.security.web.util.matcher.RegexRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
@@ -53,21 +52,22 @@ import java.io.IOException;
*
* @author Sindre Mehus
*/
-@Component(value = "restRequestParameterProcessingFilter")
public class RESTRequestParameterProcessingFilter implements Filter {
private static final Logger LOG = Logger.getLogger(RESTRequestParameterProcessingFilter.class);
private final JAXBWriter jaxbWriter = new JAXBWriter();
- @Autowired
- private ProviderManager authenticationManager;
- @Autowired
- private SettingsService settingsService;
- @Autowired
+ private AuthenticationManager authenticationManager;
private SecurityService securityService;
- @Autowired
private LoginFailureLogger loginFailureLogger;
+ private static RequestMatcher requiresAuthenticationRequestMatcher = new RegexRequestMatcher("/rest/.+\\.view\\??.*",null);
+
+ protected boolean requiresAuthentication(HttpServletRequest request,
+ HttpServletResponse response) {
+ return requiresAuthenticationRequestMatcher.matches(request);
+ }
+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)) {
throw new ServletException("Can only process HttpServletRequest");
@@ -79,6 +79,13 @@ public class RESTRequestParameterProcessingFilter implements Filter {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
+ if (!requiresAuthentication(httpRequest, httpResponse)) {
+ chain.doFilter(request, response);
+
+ return;
+ }
+
+
String username = StringUtils.trimToNull(httpRequest.getParameter("u"));
String password = decrypt(StringUtils.trimToNull(httpRequest.getParameter("p")));
String salt = StringUtils.trimToNull(httpRequest.getParameter("s"));
@@ -192,4 +199,21 @@ public class RESTRequestParameterProcessingFilter implements Filter {
public void destroy() {
}
+
+ public void setAuthenticationManager(AuthenticationManager authenticationManager) {
+ this.authenticationManager = authenticationManager;
+ }
+
+ public SecurityService getSecurityService() {
+ return securityService;
+ }
+
+ public void setSecurityService(SecurityService securityService) {
+ this.securityService = securityService;
+ }
+
+
+ public void setLoginFailureLogger(LoginFailureLogger loginFailureLogger) {
+ this.loginFailureLogger = loginFailureLogger;
+ }
}
diff --git a/libresonic-main/src/main/java/org/libresonic/player/security/WebSecurityConfig.java b/libresonic-main/src/main/java/org/libresonic/player/security/WebSecurityConfig.java
new file mode 100644
index 00000000..890c527d
--- /dev/null
+++ b/libresonic-main/src/main/java/org/libresonic/player/security/WebSecurityConfig.java
@@ -0,0 +1,92 @@
+package org.libresonic.player.security;
+
+import org.libresonic.player.service.SecurityService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+@Configuration
+@EnableWebSecurity
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Autowired
+ private SecurityService securityService;
+ @Autowired
+ private CsrfSecurityRequestMatcher csrfSecurityRequestMatcher;
+ @Autowired
+ LoginFailureLogger loginFailureLogger;
+
+ @Override
+ @Bean(name = "authenticationManager")
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return super.authenticationManagerBean();
+ }
+
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth.userDetailsService(securityService);
+ }
+
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+
+ RESTRequestParameterProcessingFilter restAuthenticationFilter = new RESTRequestParameterProcessingFilter();
+ restAuthenticationFilter.setAuthenticationManager((AuthenticationManager) getApplicationContext().getBean("authenticationManager"));
+ restAuthenticationFilter.setSecurityService(securityService);
+ restAuthenticationFilter.setLoginFailureLogger(loginFailureLogger);
+ http = http.addFilterBefore(restAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
+
+ http
+ .csrf()
+ .requireCsrfProtectionMatcher(csrfSecurityRequestMatcher)
+ .and().headers()
+ .frameOptions()
+ .sameOrigin()
+ .and().authorizeRequests()
+ .antMatchers("recover.view", "accessDenied.view",
+ "coverArt.view", "/hls/**", "/stream/**", "/ws/**",
+ "/share/**", "/style/**", "/icons/**",
+ "/flash/**", "/script/**", "/sonos/**", "/crossdomain.xml")
+ .permitAll()
+ .antMatchers("/personalSettings.view", "/passwordSettings.view",
+ "/playerSettings.view", "/shareSettings.view")
+ .hasRole("SETTINGS")
+ .antMatchers("/generalSettings.view","/advancedSettings.view","/userSettings.view",
+ "/musicFolderSettings.view","/networkSettings.view")
+ .hasRole("ADMIN")
+ .antMatchers("/deletePlaylist.view","/savePlaylist.view")
+ .hasRole("PLAYLIST")
+ .antMatchers("/download.view")
+ .hasRole("DOWNLOAD")
+ .antMatchers("/upload.view")
+ .hasRole("UPLOAD")
+ .antMatchers("/createShare.view")
+ .hasRole("SHARE")
+ .antMatchers("/changeCoverArt.view","/editTags.view")
+ .hasRole("COVERART")
+ .antMatchers("/setMusicFileInfo.view")
+ .hasRole("COMMENT")
+ .antMatchers("/podcastReceiverAdmin.view")
+ .hasRole("PODCAST")
+ .antMatchers("/**")
+ .hasRole("USER")
+ .anyRequest().authenticated()
+ .and().formLogin()
+ .loginPage("/login")
+ .permitAll()
+ .defaultSuccessUrl("/index.view")
+ .failureUrl("/login?error=1")
+ .usernameParameter("j_username")
+ .passwordParameter("j_password")
+ .and().rememberMe().userDetailsService(securityService).key("libresonic");
+
+ }
+}
\ No newline at end of file
diff --git a/libresonic-main/src/main/resources/applicationContext-security.xml b/libresonic-main/src/main/resources/applicationContext-security.xml
deleted file mode 100644
index 7831aa7b..00000000
--- a/libresonic-main/src/main/resources/applicationContext-security.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-
-