Merge remote-tracking branch 'origin/pr/1302'

master
Andrew DeMaria 5 years ago
commit 7058b5098d
No known key found for this signature in database
GPG Key ID: 0A3F5E91F8364EDF
  1. 4
      airsonic-main/src/main/java/org/airsonic/player/controller/HelpController.java
  2. 6
      airsonic-main/src/main/java/org/airsonic/player/dao/MediaFileDao.java
  3. 6
      airsonic-main/src/main/java/org/airsonic/player/security/CustomUserDetailsContextMapper.java
  4. 10
      airsonic-main/src/main/java/org/airsonic/player/security/GlobalSecurityConfig.java
  5. 16
      airsonic-main/src/main/java/org/airsonic/player/security/JWTAuthenticationProvider.java
  6. 20
      airsonic-main/src/main/java/org/airsonic/player/security/JWTRequestParameterProcessingFilter.java
  7. 4
      airsonic-main/src/main/java/org/airsonic/player/service/JWTSecurityService.java
  8. 2
      airsonic-main/src/main/java/org/airsonic/player/service/upnp/DispatchingContentDirectory.java
  9. 10
      airsonic-main/src/main/java/org/airsonic/player/spring/RegisterPrecompiledJSPInitializer.java
  10. 16
      airsonic-main/src/main/java/org/airsonic/player/spring/SpringLiquibase.java
  11. 1
      checkstyle.xml
  12. 7
      pom.xml

@ -50,7 +50,7 @@ import java.util.Map;
@RequestMapping("/help") @RequestMapping("/help")
public class HelpController { public class HelpController {
private static final Logger logger = LoggerFactory.getLogger(HelpController.class); private static final Logger LOG = LoggerFactory.getLogger(HelpController.class);
private static final int LOG_LINES_TO_SHOW = 50; private static final int LOG_LINES_TO_SHOW = 50;
@ -109,7 +109,7 @@ public class HelpController {
} }
return lines; return lines;
} catch (Exception e) { } catch (Exception e) {
logger.warn("Could not open log file " + logFile, e); LOG.warn("Could not open log file " + logFile, e);
return null; return null;
} }
} }

@ -42,7 +42,7 @@ import java.util.*;
*/ */
@Repository @Repository
public class MediaFileDao extends AbstractDao { public class MediaFileDao extends AbstractDao {
private static final Logger logger = LoggerFactory.getLogger(MediaFileDao.class); private static final Logger LOG = LoggerFactory.getLogger(MediaFileDao.class);
private static final String INSERT_COLUMNS = "path, folder, type, format, title, album, artist, album_artist, disc_number, " + private static final String INSERT_COLUMNS = "path, folder, type, format, title, album, artist, album_artist, disc_number, " +
"track_number, year, genre, bit_rate, variable_bit_rate, duration_seconds, file_size, width, height, cover_art_path, " + "track_number, year, genre, bit_rate, variable_bit_rate, duration_seconds, file_size, width, height, cover_art_path, " +
"parent_path, play_count, last_played, comment, created, changed, last_scanned, children_last_updated, present, " + "parent_path, play_count, last_played, comment, created, changed, last_scanned, children_last_updated, present, " +
@ -133,7 +133,7 @@ public class MediaFileDao extends AbstractDao {
*/ */
@Transactional @Transactional
public void createOrUpdateMediaFile(MediaFile file) { public void createOrUpdateMediaFile(MediaFile file) {
logger.trace("Creating/Updating new media file at {}", file.getPath()); LOG.trace("Creating/Updating new media file at {}", file.getPath());
String sql = "update media_file set " + String sql = "update media_file set " +
"folder=?," + "folder=?," +
"type=?," + "type=?," +
@ -165,7 +165,7 @@ public class MediaFileDao extends AbstractDao {
"mb_release_id=? " + "mb_release_id=? " +
"where path=?"; "where path=?";
logger.trace("Updating media file {}", Util.debugObject(file)); LOG.trace("Updating media file {}", Util.debugObject(file));
int n = update(sql, int n = update(sql,
file.getFolder(), file.getMediaType().name(), file.getFormat(), file.getTitle(), file.getAlbumName(), file.getArtist(), file.getFolder(), file.getMediaType().name(), file.getFormat(), file.getTitle(), file.getAlbumName(), file.getArtist(),

@ -40,7 +40,7 @@ public class CustomUserDetailsContextMapper implements UserDetailsContextMapper
// ~ Instance fields // ~ Instance fields
// ================================================================================================ // ================================================================================================
private final Logger logger = LoggerFactory.getLogger(CustomUserDetailsContextMapper.class); private static final Logger LOG = LoggerFactory.getLogger(CustomUserDetailsContextMapper.class);
private String passwordAttributeName = "userPassword"; private String passwordAttributeName = "userPassword";
@Autowired @Autowired
@ -56,7 +56,7 @@ public class CustomUserDetailsContextMapper implements UserDetailsContextMapper
Collection<? extends GrantedAuthority> authorities) { Collection<? extends GrantedAuthority> authorities) {
String dn = ctx.getNameInNamespace(); String dn = ctx.getNameInNamespace();
logger.debug("Mapping user details from context with DN: " + dn); LOG.debug("Mapping user details from context with DN: " + dn);
// User must be defined in Airsonic, unless auto-shadowing is enabled. // User must be defined in Airsonic, unless auto-shadowing is enabled.
User user = securityService.getUserByName(username, false); User user = securityService.getUserByName(username, false);
@ -69,7 +69,7 @@ public class CustomUserDetailsContextMapper implements UserDetailsContextMapper
newUser.setStreamRole(true); newUser.setStreamRole(true);
newUser.setSettingsRole(true); newUser.setSettingsRole(true);
securityService.createUser(newUser); securityService.createUser(newUser);
logger.info("Created local user '" + username + "' for DN " + dn); LOG.info("Created local user '" + username + "' for DN " + dn);
user = securityService.getUserByName(username, false); user = securityService.getUserByName(username, false);
} }

@ -29,7 +29,7 @@ import java.security.SecureRandom;
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class GlobalSecurityConfig extends GlobalAuthenticationConfigurerAdapter { public class GlobalSecurityConfig extends GlobalAuthenticationConfigurerAdapter {
private static Logger logger = LoggerFactory.getLogger(GlobalSecurityConfig.class); private static final Logger LOG = LoggerFactory.getLogger(GlobalSecurityConfig.class);
static final String FAILURE_URL = "/login?error=1"; static final String FAILURE_URL = "/login?error=1";
@ -65,7 +65,7 @@ public class GlobalSecurityConfig extends GlobalAuthenticationConfigurerAdapter
auth.userDetailsService(securityService); auth.userDetailsService(securityService);
String jwtKey = settingsService.getJWTKey(); String jwtKey = settingsService.getJWTKey();
if (StringUtils.isBlank(jwtKey)) { if (StringUtils.isBlank(jwtKey)) {
logger.warn("Generating new jwt key"); LOG.warn("Generating new jwt key");
jwtKey = JWTSecurityService.generateKey(); jwtKey = JWTSecurityService.generateKey();
settingsService.setJWTKey(jwtKey); settingsService.setJWTKey(jwtKey);
settingsService.save(); settingsService.save();
@ -142,15 +142,15 @@ public class GlobalSecurityConfig extends GlobalAuthenticationConfigurerAdapter
boolean development = SettingsService.isDevelopmentMode(); boolean development = SettingsService.isDevelopmentMode();
if (StringUtils.isBlank(rememberMeKey) && !development) { if (StringUtils.isBlank(rememberMeKey) && !development) {
// ...if it is empty, generate a random key on startup (default). // ...if it is empty, generate a random key on startup (default).
logger.debug("Generating a new ephemeral 'remember me' key in a secure way."); LOG.debug("Generating a new ephemeral 'remember me' key in a secure way.");
rememberMeKey = generateRememberMeKey(); rememberMeKey = generateRememberMeKey();
} else if (StringUtils.isBlank(rememberMeKey) && development) { } else if (StringUtils.isBlank(rememberMeKey) && development) {
// ...if we are in development mode, we can use a fixed key. // ...if we are in development mode, we can use a fixed key.
logger.warn("Using a fixed 'remember me' key because we're in development mode, this is INSECURE."); LOG.warn("Using a fixed 'remember me' key because we're in development mode, this is INSECURE.");
rememberMeKey = DEVELOPMENT_REMEMBER_ME_KEY; rememberMeKey = DEVELOPMENT_REMEMBER_ME_KEY;
} else { } else {
// ...otherwise, use the custom key directly. // ...otherwise, use the custom key directly.
logger.info("Using a fixed 'remember me' key from system properties, this is insecure."); LOG.info("Using a fixed 'remember me' key from system properties, this is insecure.");
} }
http http

@ -23,7 +23,7 @@ import java.util.Objects;
public class JWTAuthenticationProvider implements AuthenticationProvider { public class JWTAuthenticationProvider implements AuthenticationProvider {
private static final Logger logger = LoggerFactory.getLogger(JWTAuthenticationProvider.class); private static final Logger LOG = LoggerFactory.getLogger(JWTAuthenticationProvider.class);
private final String jwtKey; private final String jwtKey;
@ -35,7 +35,7 @@ public class JWTAuthenticationProvider implements AuthenticationProvider {
public Authentication authenticate(Authentication auth) throws AuthenticationException { public Authentication authenticate(Authentication auth) throws AuthenticationException {
JWTAuthenticationToken authentication = (JWTAuthenticationToken) auth; JWTAuthenticationToken authentication = (JWTAuthenticationToken) auth;
if (authentication.getCredentials() == null || !(authentication.getCredentials() instanceof String)) { if (authentication.getCredentials() == null || !(authentication.getCredentials() instanceof String)) {
logger.error("Credentials not present"); LOG.error("Credentials not present");
return null; return null;
} }
String rawToken = (String) auth.getCredentials(); String rawToken = (String) auth.getCredentials();
@ -45,7 +45,7 @@ public class JWTAuthenticationProvider implements AuthenticationProvider {
// TODO:AD This is super unfortunate, but not sure there is a better way when using JSP // TODO:AD This is super unfortunate, but not sure there is a better way when using JSP
if (StringUtils.contains(authentication.getRequestedPath(), "/WEB-INF/jsp/")) { if (StringUtils.contains(authentication.getRequestedPath(), "/WEB-INF/jsp/")) {
logger.warn("BYPASSING AUTH FOR WEB-INF page"); LOG.warn("BYPASSING AUTH FOR WEB-INF page");
} else if (!roughlyEqual(path.asString(), authentication.getRequestedPath())) { } else if (!roughlyEqual(path.asString(), authentication.getRequestedPath())) {
throw new InsufficientAuthenticationException("Credentials not valid for path " + authentication throw new InsufficientAuthenticationException("Credentials not valid for path " + authentication
.getRequestedPath() + ". They are valid for " + path.asString()); .getRequestedPath() + ". They are valid for " + path.asString());
@ -58,9 +58,9 @@ public class JWTAuthenticationProvider implements AuthenticationProvider {
} }
private static boolean roughlyEqual(String expectedRaw, String requestedPathRaw) { private static boolean roughlyEqual(String expectedRaw, String requestedPathRaw) {
logger.debug("Comparing expected [{}] vs requested [{}]", expectedRaw, requestedPathRaw); LOG.debug("Comparing expected [{}] vs requested [{}]", expectedRaw, requestedPathRaw);
if (StringUtils.isEmpty(expectedRaw)) { if (StringUtils.isEmpty(expectedRaw)) {
logger.debug("False: empty expected"); LOG.debug("False: empty expected");
return false; return false;
} }
try { try {
@ -68,7 +68,7 @@ public class JWTAuthenticationProvider implements AuthenticationProvider {
UriComponents requested = UriComponentsBuilder.fromUriString(requestedPathRaw).build(); UriComponents requested = UriComponentsBuilder.fromUriString(requestedPathRaw).build();
if (!Objects.equals(expected.getPath(), requested.getPath())) { if (!Objects.equals(expected.getPath(), requested.getPath())) {
logger.debug("False: expected path [{}] does not match requested path [{}]", LOG.debug("False: expected path [{}] does not match requested path [{}]",
expected.getPath(), requested.getPath()); expected.getPath(), requested.getPath());
return false; return false;
} }
@ -80,12 +80,12 @@ public class JWTAuthenticationProvider implements AuthenticationProvider {
!difference.entriesOnlyOnLeft().isEmpty() || !difference.entriesOnlyOnLeft().isEmpty() ||
difference.entriesOnlyOnRight().size() != 1 || difference.entriesOnlyOnRight().size() != 1 ||
difference.entriesOnlyOnRight().get(JWTSecurityService.JWT_PARAM_NAME) == null) { difference.entriesOnlyOnRight().get(JWTSecurityService.JWT_PARAM_NAME) == null) {
logger.debug("False: expected query params [{}] do not match requested query params [{}]", expected.getQueryParams(), requested.getQueryParams()); LOG.debug("False: expected query params [{}] do not match requested query params [{}]", expected.getQueryParams(), requested.getQueryParams());
return false; return false;
} }
} catch (Exception e) { } catch (Exception e) {
logger.warn("Exception encountered while comparing paths", e); LOG.warn("Exception encountered while comparing paths", e);
return false; return false;
} }
return true; return true;

@ -22,7 +22,7 @@ import java.io.IOException;
import java.util.Optional; import java.util.Optional;
public class JWTRequestParameterProcessingFilter implements Filter { public class JWTRequestParameterProcessingFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(JWTRequestParameterProcessingFilter.class); private static final Logger LOG = LoggerFactory.getLogger(JWTRequestParameterProcessingFilter.class);
private final AuthenticationManager authenticationManager; private final AuthenticationManager authenticationManager;
private final AuthenticationFailureHandler failureHandler; private final AuthenticationFailureHandler failureHandler;
@ -63,8 +63,8 @@ public class JWTRequestParameterProcessingFilter implements Filter {
return; return;
} }
if (logger.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
logger.debug("Request is to process authentication"); LOG.debug("Request is to process authentication");
} }
Authentication authResult; Authentication authResult;
@ -78,7 +78,7 @@ public class JWTRequestParameterProcessingFilter implements Filter {
} }
} }
catch (InternalAuthenticationServiceException failed) { catch (InternalAuthenticationServiceException failed) {
logger.error( LOG.error(
"An internal error occurred while trying to authenticate the user.", "An internal error occurred while trying to authenticate the user.",
failed); failed);
unsuccessfulAuthentication(request, response, failed); unsuccessfulAuthentication(request, response, failed);
@ -92,8 +92,8 @@ public class JWTRequestParameterProcessingFilter implements Filter {
return; return;
} }
if (logger.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: " LOG.debug("Authentication success. Updating SecurityContextHolder to contain: "
+ authResult); + authResult);
} }
@ -107,10 +107,10 @@ public class JWTRequestParameterProcessingFilter implements Filter {
throws IOException, ServletException { throws IOException, ServletException {
SecurityContextHolder.clearContext(); SecurityContextHolder.clearContext();
if (logger.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
logger.debug("Authentication request failed: " + failed.toString(), failed); LOG.debug("Authentication request failed: " + failed.toString(), failed);
logger.debug("Updated SecurityContextHolder to contain null Authentication"); LOG.debug("Updated SecurityContextHolder to contain null Authentication");
logger.debug("Delegating to authentication failure handler " + failureHandler); LOG.debug("Delegating to authentication failure handler " + failureHandler);
} }
failureHandler.onAuthenticationFailure(request, response, failed); failureHandler.onAuthenticationFailure(request, response, failed);

@ -19,7 +19,7 @@ import java.util.Date;
@Service("jwtSecurityService") @Service("jwtSecurityService")
public class JWTSecurityService { public class JWTSecurityService {
private static final Logger logger = LoggerFactory.getLogger(JWTSecurityService.class); private static final Logger LOG = LoggerFactory.getLogger(JWTSecurityService.class);
public static final String JWT_PARAM_NAME = "jwt"; public static final String JWT_PARAM_NAME = "jwt";
public static final String CLAIM_PATH = "path"; public static final String CLAIM_PATH = "path";
@ -47,7 +47,7 @@ public class JWTSecurityService {
UriComponents components = UriComponentsBuilder.fromUriString(path).build(); UriComponents components = UriComponentsBuilder.fromUriString(path).build();
String query = components.getQuery(); String query = components.getQuery();
String claim = components.getPath() + (!StringUtils.isBlank(query) ? "?" + components.getQuery() : ""); String claim = components.getPath() + (!StringUtils.isBlank(query) ? "?" + components.getQuery() : "");
logger.debug("Creating token with claim " + claim); LOG.debug("Creating token with claim " + claim);
return JWT.create() return JWT.create()
.withClaim(CLAIM_PATH, claim) .withClaim(CLAIM_PATH, claim)
.withExpiresAt(expireDate) .withExpiresAt(expireDate)

@ -44,7 +44,7 @@ import java.util.Arrays;
@Service @Service
public class DispatchingContentDirectory extends CustomContentDirectory { public class DispatchingContentDirectory extends CustomContentDirectory {
public static final Logger LOG = LoggerFactory.getLogger(DispatchingContentDirectory.class); private static final Logger LOG = LoggerFactory.getLogger(DispatchingContentDirectory.class);
public static final String CONTAINER_ID_ROOT = "0"; public static final String CONTAINER_ID_ROOT = "0";
public static final String CONTAINER_ID_PLAYLIST_PREFIX = "playlist"; public static final String CONTAINER_ID_PLAYLIST_PREFIX = "playlist";

@ -24,14 +24,14 @@ import java.nio.charset.Charset;
@Component @Component
public class RegisterPrecompiledJSPInitializer implements ServletContextInitializer { public class RegisterPrecompiledJSPInitializer implements ServletContextInitializer {
private static final Logger logger = LoggerFactory.getLogger(RegisterPrecompiledJSPInitializer.class); private static final Logger LOG = LoggerFactory.getLogger(RegisterPrecompiledJSPInitializer.class);
@Override @Override
public void onStartup(ServletContext servletContext) { public void onStartup(ServletContext servletContext) {
if (SettingsService.isDevelopmentMode()) { if (SettingsService.isDevelopmentMode()) {
logger.debug("Not registering precompiled jsps"); LOG.debug("Not registering precompiled jsps");
} else { } else {
logger.debug("Registering precompiled jsps"); LOG.debug("Registering precompiled jsps");
registerPrecompiledJSPs(servletContext); registerPrecompiledJSPs(servletContext);
} }
} }
@ -39,14 +39,14 @@ public class RegisterPrecompiledJSPInitializer implements ServletContextInitiali
private static void registerPrecompiledJSPs(ServletContext servletContext) { private static void registerPrecompiledJSPs(ServletContext servletContext) {
WebApp webApp = parseXmlFragment(); WebApp webApp = parseXmlFragment();
for (ServletDef def : webApp.getServletDefs()) { for (ServletDef def : webApp.getServletDefs()) {
logger.trace("Registering precompiled JSP: {} -> {}", def.getName(), def.getSclass()); LOG.trace("Registering precompiled JSP: {} -> {}", def.getName(), def.getSclass());
ServletRegistration.Dynamic reg = servletContext.addServlet(def.getName(), def.getSclass()); ServletRegistration.Dynamic reg = servletContext.addServlet(def.getName(), def.getSclass());
// Need to set loadOnStartup somewhere between 0 and 128. 0 is highest priority. 99 should be fine // Need to set loadOnStartup somewhere between 0 and 128. 0 is highest priority. 99 should be fine
reg.setLoadOnStartup(99); reg.setLoadOnStartup(99);
} }
for (ServletMappingDef mapping : webApp.getServletMappingDefs()) { for (ServletMappingDef mapping : webApp.getServletMappingDefs()) {
logger.trace("Mapping servlet: {} -> {}", mapping.getName(), mapping.getUrlPattern()); LOG.trace("Mapping servlet: {} -> {}", mapping.getName(), mapping.getUrlPattern());
servletContext.getServletRegistration(mapping.getName()).addMapping(mapping.getUrlPattern()); servletContext.getServletRegistration(mapping.getName()).addMapping(mapping.getUrlPattern());
} }
} }

@ -16,20 +16,20 @@ import java.sql.Connection;
import java.util.List; import java.util.List;
public class SpringLiquibase extends liquibase.integration.spring.SpringLiquibase { public class SpringLiquibase extends liquibase.integration.spring.SpringLiquibase {
private static final Logger logger = LoggerFactory.getLogger(SpringLiquibase.class); private static final Logger LOG = LoggerFactory.getLogger(SpringLiquibase.class);
@Override @Override
public void afterPropertiesSet() throws LiquibaseException { public void afterPropertiesSet() throws LiquibaseException {
logger.trace("Starting Liquibase Update"); LOG.trace("Starting Liquibase Update");
try { try {
super.afterPropertiesSet(); super.afterPropertiesSet();
} catch (Exception e) { } catch (Exception e) {
logger.error("==============================================="); LOG.error("===============================================");
logger.error("An exception occurred during database migration"); LOG.error("An exception occurred during database migration");
logger.error("A rollback file has been generated at " + rollbackFile); LOG.error("A rollback file has been generated at " + rollbackFile);
logger.error("Execute it within your database to rollback any changes"); LOG.error("Execute it within your database to rollback any changes");
logger.error("The exception is as follows\n", e); LOG.error("The exception is as follows\n", e);
logger.error("==============================================="); LOG.error("===============================================");
throw(e); throw(e);
} }
} }

@ -64,6 +64,7 @@
<property name="allowEmptyMethods" value="true"/> <property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/> <property name="allowEmptyTypes" value="true"/>
</module> </module>
<module name="org.airsonic.checkstyle.LoggerNameCheck"/>
</module> </module>
<module name="UniqueProperties"/> <module name="UniqueProperties"/>

@ -255,6 +255,13 @@
</goals> </goals>
</execution> </execution>
</executions> </executions>
<dependencies>
<dependency>
<groupId>org.airsonic</groupId>
<artifactId>checkstyle</artifactId>
<version>1.0-RELEASE</version>
</dependency>
</dependencies>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.owasp</groupId> <groupId>org.owasp</groupId>

Loading…
Cancel
Save