springboot security 集成 cas 问题 No subject alternative names present

news2024/12/23 17:37:30

springboot security 集成 cas 问题 No subject alternative names present

  • 前言
  • 一、问题
    • 1.实际问题
  • 二、大海捞针
    • 1.星星之火
    • 2.通用方法
    • 啰嗦一句
  • 解决
    • 2.新建三个类
    • 配置文件修改


前言

场景:
在一次springboot security 集成 cas开发中,代码报错:java.security.cert.CertificateException: No subject alternative names present。
环境:
springboot security 集成 cas,cas 服务是其他厂家开发,使用https 协议,所以服务端无法改动,只能在客户端排查问题。


一、问题

从错误信息得到大概意思就是在调用https请求时候校验证书异常。

说到这个问题,我自己搭建一个 https服务, 使用 jdk 自带 keytool 工具生成证书验证了一下:
要能正确的调用https 请求, 要满足
1.客户端要导入由服务端通过 keystore 导出的证书文件;
2.服务生成证书时候填写的CN 信息(域名) 和客户端访问的url的域名要一致(本地测试可以修改hosts文件配置域名)。

1.实际问题

但是!
第三方厂家 cas 服务端的https 证书就随便搞的,连CN信息都是随便写的不知道啥意思。
而且,虽是https 但还是通过ip 端口方式访问。 *哎, 这明显是应付入网安评嘛 *
让我如何是好!

二、大海捞针

1.星星之火

网上搜了很多。
只能绕过 https 证书校验去访问了。
看到一篇和我同样问题的文章:记一次单点登录https中证书无效的问题
他的方式是修改 CommonUtils 源码,然后重新编译打包替换原来的包,这种方式虽说能解决但是不通用,为啥尼,比如代码需要重新下载依赖,那还是每次都要重新替换,而且其他项目想校验证书用到了这个类,就难办了。

而且。他的答案漏了一行重要的代码,下文会提到。

2.通用方法

对于java 需要修改源码,我们一般会使用继承重写的方式。
但是对应本项目。
在这里插入图片描述
问题就出现在 CommonUtils类中 getResponseFromServer 这个方法。不能在这地方直接修改,否则只能像刚才那个网友搞了。找找到哪里用到这个地方。
往前找
在这里插入图片描述

AbstractCasProtocolUrlBasedTicketValidator.class-retrieveResponseFromServer 一看 final 修饰,没戏,再往前找。

在这里插入图片描述

AbstractUrlBasedTicketValidator.class - validate 该方法被final 修饰,重写不了。再往前

在这里插入图片描述
CasAuthenticationProvider.class - authenticateNow , 这个是 private 私有方法,重写不了。
再往前
在这里插入图片描述
CasAuthenticationProvider.class - authenticate ,哎CasAuthenticationProvider,好熟悉的眼神, 没错就是你了,在配置cas就见过你。再加上这个方法是 public,于是就重写这个方法,从这开刀。

啰嗦一句

建议新手多多学会使用 debuger, 你会发现越来越上瘾
在这里插入图片描述


解决

2.新建三个类

在这里插入图片描述
CasAuthenticationProviderExt

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package cn.com.liyx.learn.lyxsec.ext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidationException;
import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.*;
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.core.userdetails.*;
import org.springframework.util.Assert;

public class CasAuthenticationProviderExt extends CasAuthenticationProvider {
    private static final Log logger = LogFactory.getLog(CasAuthenticationProvider.class);
    private final UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
    private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
    private Cas20ProxyTicketValidatorExt ticketValidator;

    private ServiceProperties serviceProperties;

    public void afterPropertiesSet() {
        Assert.notNull(this.ticketValidator, "A ticketValidator must be set");
    }

    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        if (!this.supports(authentication.getClass())) {
            return null;
        } else if (authentication instanceof UsernamePasswordAuthenticationToken && !"_cas_stateful_".equals(authentication.getPrincipal().toString()) && !"_cas_stateless_".equals(authentication.getPrincipal().toString())) {
            return null;
        } else if (authentication instanceof CasAuthenticationToken) {
            if (getKey().hashCode() == ((CasAuthenticationToken) authentication).getKeyHash()) {
                return authentication;
            } else {
                throw new BadCredentialsException(this.messages.getMessage("CasAuthenticationProviderExt.incorrectKey", "The presented CasAuthenticationToken does not contain the expected key"));
            }
        } else if (authentication.getCredentials() != null && !"".equals(authentication.getCredentials())) {
            boolean stateless = false;
            if (authentication instanceof UsernamePasswordAuthenticationToken && "_cas_stateless_".equals(authentication.getPrincipal())) {
                stateless = true;
            }

            CasAuthenticationToken result = null;
            if (stateless) {
                result = getStatelessTicketCache().getByTicketId(authentication.getCredentials().toString());
            }

            if (result == null) {
                result = this.authenticateNow(authentication);
                result.setDetails(authentication.getDetails());
            }

            if (stateless) {
                getStatelessTicketCache().putTicketInCache(result);
            }

            return result;
        } else {
            throw new BadCredentialsException(this.messages.getMessage("CasAuthenticationProviderExt.noServiceTicket", "Failed to provide a CAS service ticket to validate"));
        }
    }

    private CasAuthenticationToken authenticateNow(Authentication authentication) throws AuthenticationException {
        try {
            Assertion assertion = this.ticketValidator.validate2(authentication.getCredentials().toString(), this.getServiceUrl(authentication));
            UserDetails userDetails = this.loadUserByAssertion(assertion);
            userDetailsChecker.check(userDetails);
            return new CasAuthenticationToken(getKey(), userDetails, authentication.getCredentials(), this.authoritiesMapper.mapAuthorities(userDetails.getAuthorities()), userDetails, assertion);
        } catch (TicketValidationException var4) {
            throw new BadCredentialsException(var4.getMessage(), var4);
        }
    }

    private String getServiceUrl(Authentication authentication) {
        String serviceUrl;
        if (authentication.getDetails() instanceof ServiceAuthenticationDetails) {
            serviceUrl = ((ServiceAuthenticationDetails) authentication.getDetails()).getServiceUrl();
        } else {
            if (this.serviceProperties == null) {
                throw new IllegalStateException("serviceProperties cannot be null unless Authentication.getDetails() implements ServiceAuthenticationDetails.");
            }

            if (this.serviceProperties.getService() == null) {
                throw new IllegalStateException("serviceProperties.getService() cannot be null unless Authentication.getDetails() implements ServiceAuthenticationDetails.");
            }

            serviceUrl = this.serviceProperties.getService();
        }

        if (logger.isDebugEnabled()) {
            logger.debug("serviceUrl = " + serviceUrl);
        }

        return serviceUrl;
    }

    public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
        this.authoritiesMapper = authoritiesMapper;
    }

    public void setServiceProperties(ServiceProperties serviceProperties) {
        this.serviceProperties = serviceProperties;
    }

    protected Cas20ProxyTicketValidatorExt getTicketValidator() {
        return this.ticketValidator;
    }

    public void setTicketValidator(Cas20ProxyTicketValidatorExt ticketValidator) {
        this.ticketValidator = ticketValidator;
    }
}

Cas20ProxyTicketValidatorExt

package cn.com.liyx.learn.lyxsec.ext;

import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Cas20ProxyTicketValidator;
import org.jasig.cas.client.validation.TicketValidationException;

import java.net.MalformedURLException;
import java.net.URL;

public class Cas20ProxyTicketValidatorExt extends Cas20ProxyTicketValidator {
    public Cas20ProxyTicketValidatorExt(String casServerUrlPrefix) {
        super(casServerUrlPrefix);
    }

    public final Assertion validate2(String ticket, String service) throws TicketValidationException {
        String validationUrl = this.constructValidationUrl(ticket, service);
        this.logger.debug("Constructing validation url: {}", validationUrl);

        try {
            this.logger.debug("Retrieving response from server.");
//            String serverResponse = this.retrieveResponseFromServer(new URL(validationUrl), ticket);
            String serverResponse = CommonUtilsExt.getResponseFromServer(new URL(validationUrl), this.getURLConnectionFactory(), this.getEncoding());
            if (serverResponse == null) {
                throw new TicketValidationException("The CAS server returned no response.");
            } else {
                this.logger.debug("Server response: {}", serverResponse);
                return this.parseResponseFromServer(serverResponse);
            }
        } catch (MalformedURLException var5) {
            throw new TicketValidationException(var5);
        }
    }
}

CommonUtilsExt

package cn.com.liyx.learn.lyxsec.ext;

import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
import org.jasig.cas.client.util.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

public class CommonUtilsExt {
    private static final Logger LOGGER = LoggerFactory.getLogger(CommonUtils.class);

    static {
        disableSslVerification();
    }

    private static void disableSslVerification() {
        try {
            // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }

                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            }
            };
            // Install the all-trusting trust manager
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            // Create all-trusting host name verifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
            // Install the all-trusting host verifier
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
    }

    public static String getResponseFromServer(URL constructedUrl, HttpURLConnectionFactory factory, String encoding) {

        HttpURLConnection conn = null;
        InputStreamReader in = null;

        try {
//            conn = factory.buildHttpURLConnection(constructedUrl.openConnection());  // 原来的写法。
            conn = (HttpURLConnection) constructedUrl.openConnection();  // 新的写法, (注)本文要这样的写法
            if (CommonUtils.isEmpty(encoding)) {
                in = new InputStreamReader(conn.getInputStream());
            } else {
                in = new InputStreamReader(conn.getInputStream(), encoding);
            }

            StringBuilder builder = new StringBuilder(255);

            int byteRead;
            while ((byteRead = in.read()) != -1) {
                builder.append((char) byteRead);
            }
            String var7 = builder.toString();
            return var7;
        } catch (RuntimeException var13) {
            throw var13;
        } catch (SSLException var14) {
            LOGGER.error("SSL error getting response from host: {} : Error Message: {}", new Object[]{constructedUrl.getHost(), var14.getMessage(), var14});
            throw new RuntimeException(var14);
        } catch (IOException var15) {
            LOGGER.error("Error getting response from host: [{}] with path: [{}] and protocol: [{}] Error Message: {}", new Object[]{constructedUrl.getHost(), constructedUrl.getPath(), constructedUrl.getProtocol(), var15.getMessage(), var15});
            throw new RuntimeException(var15);
        } finally {
            CommonUtils.closeQuietly(in);
            if (conn != null) {
                conn.disconnect();
            }

        }
    }

}

前面说那个网友漏掉重要一行, 就是下图这一行, 确实重要!!!
在这里插入图片描述

配置文件修改

在这里插入图片描述

注意就是方法返回类型 以及 属性类型也需要用新增的类名,不然会莫名报错。

完工。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/14724.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

轻松掌握 jQuery 基础

文章目录💖 前言💖 jQuery简介💖 jQuery安装及使用💖 jQuery的$💞 选择器💞 功能函数前缀💞 window.onload💞 创建DOM元素💖 投票快捷键💖 前言 随着JavaScri…

手机怎么把图片转换成Word?这个小妙招大家要学会

使用手机怎么把图片转换成Word文档呢?大家在使用图片文件来办公的时候,有的图片里面有成段成段的文字,不仅阅读起来很不方便,还很难修改内容,这时候我们可以将图片里的内容转换成Word文档,就可以解决这一问…

利用gdal把多张tif合成一张大图

目录gdalwarpgdalbuildvrt有时候从网站下载遥感影像时,因为选定区域的遥感影像太大,下载后往往是自动就给切片下载了。特别是当选定区域特别大时,最后形成的切片会有几十甚至上百小块,且这些小块都没有重叠的地方,虽然…

MySQL8.0优化 - 事务的ACID特性

文章目录学习资料事务事务的ACID特性原子性(atomicity)一致性(consistency)隔离性(isolation)持久性总结学习资料 【MySQL数据库教程天花板,mysql安装到mysql高级,强!硬…

以梦为马,不负韶华|电巢科技延安大学飞鹰计划实习班精彩回顾

时光流淌无声,昨天仿佛还初次见面,今天却又是一年的尾声。你是否结交到亲密的小伙伴?你是否感受到团队合作的魅力?你是否在延大这片沃土得到成长?假如你还没答案,那么看看其他人的回答。 在延安大学&#x…

node深度打印对象

Node 深度打印对象 在node中打印对象类型时,如果对象的层级过深,就会出现这样的问题 要想显示里面的值,就要通过JSON.stringify方法 这样打印出来不易于阅读且不美观,可以设置参数的方式来格式化JSON console.log(JSON.string…

【计算机组成原理】第三章单元测试

1.单选(2分) ‎执行算术右移指令的操作过程是 ‍A.操作数的符号位不变,各位顺次右移1位,符号位拷贝至最高数据位 B.操作数的符号位填0,各位顺次右移1位 C.操作数的符号位填1,各位顺次右移1位 D.进位标志移至符号位&#xff0…

九、Vue3基础之九

文章目录一、可视化1.1 接口API 也是后端项目1.2 前端项目开始1.2.1 echarts二、Vue3 Router2.1 Router的初步应用2.2 路由模式、Router原理2.3 命名路由、编程式导航2.4 历史记录2.5 路由传参2.6 嵌套路由2.7 命名视图2.8 重定向、别名2.9 导航守卫(前置守卫&#…

SpringBoot整合dubbo(三)

整合nacos作为注册中心 一、下载nacos:Release 2.2.0-BETA (Oct 28, 2022) alibaba/nacos GitHub 1.1、直接启动时报错,需要指定单例启动:startup.cmd -m standalone 启动后在http://localhost:8848/nacos/index.html访问,默认…

Revit中记忆快速修改未识别的梁及“快速生成过梁”

一、Revit中记忆快速修改未识别的梁 我们在使用红瓦建模大师对结构梁进行翻模时,往往会出现梁未识别的情况(如图 1),这需要我们人工手动去修改。图中这一跨梁的命名应该同 KL5 (2B),只是尺寸不同,只需要将它替换成前一跨梁然后复制…

计算机网络—概述

互联网 互联网又称国际网络,指的是网络与网络之间所串连成的庞大网络,这些网络以一组通用的协议相连,形成逻辑上的单一巨大国际网络。简单的说,网络把主机连接起来,互联网就是把多种不同的网络连接起来。 ISP 互联…

分布式天花板?阿里百万架构师的ZK+Dubbo笔记,颠覆认知

蓦然回首自己做开发已经十年了,这十年中我获得了很多,技术能力、培训、出国、大公司的经历,还有很多很好的朋友。但再仔细一想,这十年中我至少浪费了五年时间,这五年可以足够让自己成长为一个优秀的程序员,…

Java语言知识大盘点(期末复习)一

🌹作者:云小逸 📝个人主页:云小逸的主页 📝Github:云小逸的Github 🤟motto:要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前…

卡方检验简介

Chi square test(卡方检验)是用于评价两类变量之间是否存在相关性的统计检验方法。 医疗研究会产生大量不同类型的数据,最容易识别的是定量的数据。例如,直腿抬高 (SLR) 的受试者能够将腿抬高大于 0 度,这让我们可以计…

[附源码]Python计算机毕业设计JAVA疫情社区管理系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

大黄酸偶联鸡卵白蛋白 rhein-OVA,BFNB/MEB/MEA/BFNH-OVA

产品名称:大黄酸偶联鸡卵白蛋白 英文名称: rhein-OVA 用途:科研 状态:固体/粉末/溶液 产品规格:1g/5g/10g 保存:冷藏 储藏条件:-20℃ 储存时间:1年 大黄酸是一种有机化合物&#xf…

华为机试 - 堆栈中的剩余数字

目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 向一个空栈中依次存入正整数&#xff0c;假设入栈元素 n(1<n<2^31-1)按顺序依次为 nx…n4、 n3、n2、 n1, 每当元素入栈时&#xff0c;如果 n1n2…ny(y 的范围[2,x]&#xff0c; 1<x<1000…

Windows平台上安装MySql 5.6 /8.0等的各种问题解决办法汇总

又是几个月过去了,我依然没有更新博客,深深的内疚缠绕着我,我对不起关注我的各位朋友们,从现在开始,我又回来了,正确能频繁的给大家带来新的知识点或小技巧。 📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创…

一本书读懂大数据 读书笔记(1)

集。谷歌的MapReduce和GoogleFileSystem(GFS)发布了之后&#xff0c;大数据的定义中除了 涵盖大量数据之外&#xff0c;还包括数据处理的速度。 网络搜索索引&#xff0c;批量处理和分析大量数据集&#xff0c;数据处理的速度 研究机构Gartner曾给大数据&#xff08;Big data…

照片一键换天空怎么弄?不妨试试这三个照片一键换天空方法

小伙伴们有没有遇到过这样的情况&#xff0c;好不容易遇到假期&#xff0c;约了朋友一起外出游玩&#xff0c;想要拍一些好看的照片&#xff0c;奈何天空阴沉沉的&#xff0c;导致拍出的照片不太理想&#xff0c;又不想放弃这个难得的假期&#xff0c;有没有什么方法可以换照片…