I made a patch to Subsonic 3.9 that will allow HTTP Basic Authentication to the REST web services, so you don't have to use the "p" and "u" parameters.
The patch also makes it possible to run the application in jetty, when developing and testing. To run jetty, execute this from the subsonic-main directory:
- Code: Select all
mvn jetty:run -Dsubsonic.home=/tmp/subsonic-test
- Code: Select all
diff --git a/subsonic-main/pom.xml b/subsonic-main/pom.xml
index 5e2eccf..e7e97e7 100644
--- a/subsonic-main/pom.xml
+++ b/subsonic-main/pom.xml
@@ -275,6 +275,26 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-test</artifactId>
+ <version>2.5.6</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty</artifactId>
+ <version>6.1.5</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>servlet-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
</dependencies>
<profiles>
@@ -329,6 +349,20 @@
</executions>
</plugin>
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>maven-jetty-plugin</artifactId>
+ <version>6.1.16</version>
+ <configuration>
+ <connectors>
+ <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
+ <port>8181</port>
+ <maxIdleTime>6000</maxIdleTime>
+ </connector>
+ </connectors>
+ </configuration>
+ </plugin>
+
</plugins>
</build>
</project>
diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/security/RESTRequestParameterProcessingFilter.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/security/RESTRequestParameterProcessingFilter.java
index 659d121..9f23090 100644
--- a/subsonic-main/src/main/java/net/sourceforge/subsonic/security/RESTRequestParameterProcessingFilter.java
+++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/security/RESTRequestParameterProcessingFilter.java
@@ -75,6 +75,8 @@ public class RESTRequestParameterProcessingFilter implements Filter {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
+ Authentication previousAuth = SecurityContextHolder.getContext().getAuthentication();
+
String username = StringUtils.trimToNull(httpRequest.getParameter("u"));
String password = decrypt(StringUtils.trimToNull(httpRequest.getParameter("p")));
String version = StringUtils.trimToNull(httpRequest.getParameter("v"));
@@ -82,7 +84,25 @@ public class RESTRequestParameterProcessingFilter implements Filter {
RESTController.ErrorCode errorCode = null;
- if (username == null || password == null || version == null || client == null) {
+ if (previousAuth == null) {
+ /*
+ * The username and password parameters are not required if the user
+ * was previously authenticated, for example using Basic Auth
+ */
+ if (username == null || password == null) {
+ errorCode = RESTController.ErrorCode.MISSING_PARAMETER;
+ }
+ } else {
+ if (username != null || password != null) {
+ LOG.warn("Username and password provided in URL params, "
+ + "but discarded. User already authenticated as "
+ + previousAuth.getName());
+ }
+
+ username = previousAuth.getName();
+ }
+
+ if (version == null || client == null) {
errorCode = RESTController.ErrorCode.MISSING_PARAMETER;
}
@@ -90,7 +110,9 @@ public class RESTRequestParameterProcessingFilter implements Filter {
errorCode = checkAPIVersion(version);
}
- if (errorCode == null) {
+ if (previousAuth != null) {
+ // Already authenticated
+ } else if (errorCode == null) {
errorCode = authenticate(username, password);
}
@@ -202,4 +224,4 @@ public class RESTRequestParameterProcessingFilter implements Filter {
public void setSettingsService(SettingsService settingsService) {
this.settingsService = settingsService;
}
-}
\ No newline at end of file
+}
diff --git a/subsonic-main/src/main/webapp/WEB-INF/applicationContext-security.xml b/subsonic-main/src/main/webapp/WEB-INF/applicationContext-security.xml
index 460fa3a..560be60 100644
--- a/subsonic-main/src/main/webapp/WEB-INF/applicationContext-security.xml
+++ b/subsonic-main/src/main/webapp/WEB-INF/applicationContext-security.xml
@@ -11,7 +11,7 @@
/wap**=httpSessionContextIntegrationFilter,logoutFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,basicExceptionTranslationFilter,filterInvocationInterceptor
/podcastReceiver**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
/podcast**=httpSessionContextIntegrationFilter,logoutFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,basicExceptionTranslationFilter,filterInvocationInterceptor
- /rest/**=httpSessionContextIntegrationFilter,logoutFilter,restRequestParameterProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,basicExceptionTranslationFilter,filterInvocationInterceptor
+ /rest/**=httpSessionContextIntegrationFilter,logoutFilter,basicProcessingFilter,restRequestParameterProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,basicExceptionTranslationFilter,filterInvocationInterceptor
/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>