I am trying to use Spring Security 3.0.5 in my web application. Basically, I want to have a web service which return data in json format via HTTP GET
.
I
I have solved my problem so I think I should share it here. This configuration allows server to send out error message differently depending on the requesting software. If the request comes from a web browser, it will check the User-Agent
header and redirect to a form login if necessary. If the request comes from, for example, curl
, it will print out plain text error message when the authentication fails.
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<!-- AspectJ pointcut expression that locates our "post" method and applies security that way
<protect-pointcut expression="execution(* bigbank.*Service.post*(..))" access="ROLE_TELLER"/>-->
<sec:global-method-security secured-annotations="enabled"/>
<bean id="basicAuthenticationFilter"
class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter"
p:authenticationManager-ref="authenticationManager"
p:authenticationEntryPoint-ref="basicAuthenticationEntryPoint" />
<bean id="basicAuthenticationEntryPoint"
class="webapp.PlainTextBasicAuthenticationEntryPoint"
p:realmName="myWebapp"/>
<bean id="formAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
p:loginFormUrl="/login.jsp"/>
<bean id="daep" class="org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint">
<constructor-arg>
<map>
<entry key="hasHeader('User-Agent','Mozilla') or hasHeader('User-Agent','Opera') or hasHeader('User-Agent','Explorer')" value-ref="formAuthenticationEntryPoint" />
</map>
</constructor-arg>
<property name="defaultEntryPoint" ref="basicAuthenticationEntryPoint"/>
</bean>
<sec:http entry-point-ref="daep">
<sec:intercept-url pattern="/login.jsp*" filters="none"/>
<sec:intercept-url pattern="/json" access="ROLE_USER,ROLE_ADMIN" />
<sec:intercept-url pattern="/json/*" access="ROLE_USER,ROLE_ADMIN" />
<sec:logout
logout-url="/logout"
logout-success-url="/home.jsp"/>
<sec:form-login
login-page="/login.jsp"
login-processing-url="/login"
authentication-failure-url="/login.jsp?login_error=1" default-target-url="/home.jsp"/>
<sec:custom-filter position="BASIC_AUTH_FILTER" ref="basicAuthenticationFilter" />
</sec:http>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider>
...
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
PlainTextBasicAuthenticationEntryPoint
by extending org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
public class PlainTextBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\"");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter writer = response.getWriter();
writer.println("HTTP Status " + HttpServletResponse.SC_UNAUTHORIZED + " - " + authException.getMessage());
}
}
I am wondering if it is ever making it to your AccessDeniedHandler. Is the error because of Authentication or Authorization? Does the AccessDeniedHandeler get called for both scenarios? I am in the process of solving this myself right now.