Handle unauthorized error message for Basic Authentication in Spring Security

java spring-security
26,326

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());
    }
}
Share:
26,326
gigadot
Author by

gigadot

This is blank.

Updated on July 12, 2022

Comments

  • gigadot
    gigadot almost 2 years

    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 have implemented a RESTful service which returns data when the url http://localhost:8080/webapp/json is requested. This works fine with the following curl command

    > curl http://localhost:8080/webapp/json
    {"key":"values"}
    

    After I added basic authentication using spring security, I can use following commands to get the data

    > curl  http://localhost:8080/webapp/json
    <html><head><title>Apache Tomcat/6.0.29 - Error report .....
    > curl -u username:password http://localhost:8080/webapp/json
    {"key":"values"}
    

    The former command returns standard tomcat error page since now it requires username and password. My question is whether it is possible to handle access denied in such a way that it prints out my own error message? i.e.

    > curl  http://localhost:8080/webapp/json
    {"error":"401", "message":"Username and password required"}
    

    Here is my spring security configuration and AccessDeniedHandler. As you can see, I am trying to add access-denied-handler which simply prints out a string through servlet response but it still does not print my own message on command line.

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security"
           xmlns:beans="http://www.springframework.org/schema/beans"
           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">
        <global-method-security secured-annotations="enabled"/>
    
        <beans:bean name="access-denied" class="webapp.error.JSONAccessDeniedHandler"></beans:bean>
    
        <http auto-config="true">
            <access-denied-handler ref="access-denied"/>
            <intercept-url pattern="/json" access="ROLE_USER,ROLE_ADMIN"  />
            <http-basic />
        </http>
    
        <authentication-manager>
            <authentication-provider>
                <password-encoder hash="md5"/>
                <user-service>
                ...
                </user-service>
            </authentication-provider>
        </authentication-manager>
    
    </beans:beans>
    

    AccessDeniedHandler.java

    package webapp.error;
    
    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.access.AccessDeniedException;
    import org.springframework.security.web.access.AccessDeniedHandler;
    
    public class JSONAccessDeniedHandler implements AccessDeniedHandler  {
    
        @Override
        public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
            PrintWriter writer = response.getWriter();
            writer.print("{\"error\":\"401\", \"message\":\"Username and password required\"}");
        }
    
    }
    

Recents

Why Is PNG file with Drop Shadow in Flutter Web App Grainy?
How to troubleshoot crashes detected by Google Play Store for Flutter app
Cupertino DateTime picker interfering with scroll behaviour
Why does awk -F work for most letters, but not for the letter "t"?
Flutter change focus color and icon color but not works
How to print and connect to printer using flutter desktop via usb?
Critical issues have been reported with the following SDK versions: com.google.android.gms:play-services-safetynet:17.0.0
Flutter Dart - get localized country name from country code
navigatorState is null when using pushNamed Navigation onGenerateRoutes of GetMaterialPage
Android Sdk manager not found- Flutter doctor error
Flutter Laravel Push Notification without using any third party like(firebase,onesignal..etc)
How to change the color of ElevatedButton when entering text in TextField

Related

HTTP Status 403 - Expected CSRF token not found. Has your session expired?
Show SQL errors of Spring-security in tomcat
spring security get user id from DB
Property 'userDetailsService': no matching editors or conversion strategy found
Integrating Spring Security with SiteMinder
Spring security application of antMatcher() vs. antMatchers()
Spring Security Oauth2: Flow to Handling Expired AccessToken
Spring Security get user info in rest service, for authenticated and not authenticated users
How to enable CORS at Spring Security level in Spring boot
MVC interceptor vs Spring security filter vs something else...?

两个鬼故事品牌茶叶起名大全众泰激光神力无敌东湖高新技术开发区崔姓男孩起名字大全男孩蜀道难翻译吴姓起名100分的名字大全榕字起名最新公司起名大全免费登记注册身份验证大雁塔喷泉开放时间祖字正辈男孩起名柴犬起名年属猪的的宝宝起名宜用字恐鸟民国第一军阀土方岁三企业管理咨询公司起名起名带水字的成都公司取名起名大全我的时代你的时代小说商贸公司起名用字大全三字姓薛男起名字郑州善如意起名怎么样商家起名大全男气功名字三个字牌子起名起名大师软件下载子扬起名的含义是什么rank函数少年生前被连续抽血16次?多部门介入两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”淀粉肠小王子日销售额涨超10倍高中生被打伤下体休学 邯郸通报单亲妈妈陷入热恋 14岁儿子报警何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言张家界的山上“长”满了韩国人?男孩8年未见母亲被告知被遗忘中国拥有亿元资产的家庭达13.3万户19岁小伙救下5人后溺亡 多方发声315晚会后胖东来又人满为患了张立群任西安交通大学校长“重生之我在北大当嫡校长”男子被猫抓伤后确诊“猫抓病”测试车高速逃费 小米:已补缴周杰伦一审败诉网易网友洛杉矶偶遇贾玲今日春分倪萍分享减重40斤方法七年后宇文玥被薅头发捞上岸许家印被限制高消费萧美琴窜访捷克 外交部回应联合利华开始重组专访95后高颜值猪保姆胖东来员工每周单休无小长假男子被流浪猫绊倒 投喂者赔24万小米汽车超级工厂正式揭幕黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发当地回应沈阳致3死车祸车主疑毒驾恒大被罚41.75亿到底怎么缴妈妈回应孩子在校撞护栏坠楼外国人感慨凌晨的中国很安全杨倩无缘巴黎奥运校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变王树国卸任西安交大校长 师生送别手机成瘾是影响睡眠质量重要因素国产伟哥去年销售近13亿阿根廷将发行1万与2万面值的纸币兔狲“狲大娘”因病死亡遭遇山火的松茸之乡“开封王婆”爆火:促成四五十对奥巴马现身唐宁街 黑色着装引猜测考生莫言也上北大硕士复试名单了德国打算提及普京时仅用姓名天水麻辣烫把捣辣椒大爷累坏了

两个鬼故事 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化