Spring security configuration has moved to java.
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
+35
-11
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
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.xsd
|
||||
http://www.springframework.org/schema/security
|
||||
http://www.springframework.org/schema/security/spring-security-4.1.xsd">
|
||||
|
||||
<security:http auto-config='true'>
|
||||
|
||||
<security:csrf request-matcher-ref="csrfSecurityRequestMatcher"/>
|
||||
|
||||
|
||||
<security:headers>
|
||||
<security:frame-options policy="SAMEORIGIN"/>
|
||||
</security:headers>
|
||||
|
||||
<!-- permitAll -->
|
||||
<security:intercept-url pattern="/login.*" access="permitAll"/>
|
||||
<security:intercept-url pattern="/recover.view" access="permitAll" />
|
||||
<security:intercept-url pattern="/accessDenied.view" access="permitAll" />
|
||||
<security:intercept-url pattern="/coverArt.view" access="permitAll" />
|
||||
<security:intercept-url pattern="/hls/**" access="permitAll" />
|
||||
<security:intercept-url pattern="/stream/**" access="permitAll" />
|
||||
<security:intercept-url pattern="/ws/**" access="permitAll" />
|
||||
<security:intercept-url pattern="/rest/**" access="permitAll" />
|
||||
<security:intercept-url pattern="/share/**" access="permitAll" />
|
||||
<security:intercept-url pattern="/style/**" access="permitAll" />
|
||||
<security:intercept-url pattern="/icons/**" access="permitAll" />
|
||||
<security:intercept-url pattern="/flash/**" access="permitAll" />
|
||||
<security:intercept-url pattern="/script/**" access="permitAll" />
|
||||
<security:intercept-url pattern="/sonos/**" access="permitAll" />
|
||||
<security:intercept-url pattern="/crossdomain.xml" access="permitAll" />
|
||||
|
||||
<!-- hasRole('ROLE_SETTINGS') -->
|
||||
<security:intercept-url pattern="/personalSettings.view" access="hasRole('ROLE_SETTINGS')" />
|
||||
<security:intercept-url pattern="/passwordSettings.view" access="hasRole('ROLE_SETTINGS')" />
|
||||
<security:intercept-url pattern="/playerSettings.view" access="hasRole('ROLE_SETTINGS')" />
|
||||
<security:intercept-url pattern="/shareSettings.view" access="hasRole('ROLE_SETTINGS')" />
|
||||
|
||||
<!-- hasRole('ROLE_ADMIN') -->
|
||||
<security:intercept-url pattern="/generalSettings.view" access="hasRole('ROLE_ADMIN')" />
|
||||
<security:intercept-url pattern="/advancedSettings.view" access="hasRole('ROLE_ADMIN')" />
|
||||
<security:intercept-url pattern="/userSettings.view" access="hasRole('ROLE_ADMIN')" />
|
||||
<security:intercept-url pattern="/musicFolderSettings.view" access="hasRole('ROLE_ADMIN')" />
|
||||
<security:intercept-url pattern="/networkSettings.view" access="hasRole('ROLE_ADMIN')" />
|
||||
<security:intercept-url pattern="/dlnaSettings.view" access="hasRole('ROLE_ADMIN')" />
|
||||
<security:intercept-url pattern="/sonosSettings.view" access="hasRole('ROLE_ADMIN')" />
|
||||
<security:intercept-url pattern="/transcodingSettings.view" access="hasRole('ROLE_ADMIN')" />
|
||||
<security:intercept-url pattern="/internetRadioSettings.view" access="hasRole('ROLE_ADMIN')" />
|
||||
<security:intercept-url pattern="/podcastSettings.view" access="hasRole('ROLE_ADMIN')" />
|
||||
<security:intercept-url pattern="/db.view" access="hasRole('ROLE_ADMIN')" />
|
||||
|
||||
<!-- MISC -->
|
||||
<security:intercept-url pattern="/deletePlaylist.view" access="hasRole('ROLE_PLAYLIST')" />
|
||||
<security:intercept-url pattern="/savePlaylist.view" access="hasRole('ROLE_PLAYLIST')" />
|
||||
<security:intercept-url pattern="/download.view" access="hasRole('ROLE_DOWNLOAD')" />
|
||||
<security:intercept-url pattern="/upload.view" access="hasRole('ROLE_UPLOAD')" />
|
||||
<security:intercept-url pattern="/createShare.view" access="hasRole('ROLE_SHARE')" />
|
||||
<security:intercept-url pattern="/changeCoverArt.view" access="hasRole('ROLE_COVERART')" />
|
||||
<security:intercept-url pattern="/editTags.view" access="hasRole('ROLE_COVERART')" />
|
||||
<security:intercept-url pattern="/setMusicFileInfo.view" access="hasRole('ROLE_COMMENT')" />
|
||||
<security:intercept-url pattern="/podcastReceiverAdmin.view" access="hasRole('ROLE_PODCAST')" />
|
||||
|
||||
<!-- ROLE_USER -->
|
||||
<security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
|
||||
<security:form-login login-page="/login.view"
|
||||
default-target-url="/index.view"
|
||||
authentication-failure-url="/login.view?error=1"
|
||||
always-use-default-target="true"
|
||||
username-parameter="j_username"
|
||||
password-parameter="j_password"/>
|
||||
<security:remember-me user-service-ref="securityService" key="libresonic"/>
|
||||
</security:http>
|
||||
|
||||
<security:authentication-manager>
|
||||
<security:authentication-provider user-service-ref="securityService" />
|
||||
</security:authentication-manager>
|
||||
</beans>
|
||||
@@ -12,7 +12,7 @@
|
||||
</head>
|
||||
<body class="mainframe bgcolor1" onload="document.getElementById('j_username').focus()">
|
||||
|
||||
<form action="login" method="POST">
|
||||
<form action="/login" method="POST">
|
||||
|
||||
<sec:csrfInput />
|
||||
<div class="bgcolor2 shadow" align="center" style="padding:20px 50px 20px 50px; margin-top:100px;margin-left:50px;margin-right:50px">
|
||||
|
||||
Reference in New Issue
Block a user