搭建csa客户端
- 环境:CAS服务端
- hosts文件中配置:
127.0.0.1 cas.example.org
springboot + cas
- 导入依赖包
<dependency>
<groupId>net.unicon.cas</groupId>
<artifactId>cas-client-autoconfig-support</artifactId>
<version>1.4.0-GA</version>
</dependency>
- 在application.properties文件中添加如下配置
cas.server-url-prefix=https://cas.example.org:8443/cas
cas.server-login-url=https://cas.example.org:8443/cas/login
cas.client-host-url=http://cas.example.org:8088
cas.validation-type=CAS
cas.use-session=true
cas.redirect-after-validation=true
- 启动项目,访问http://cas.example.org:8088,会跳转到cas服务端进行登陆,登陆后跳回访问的网页。
遇到的问题
未认证授权的服务
- 访问客户端时跳转到cas服务端显示未认证授权的服务,内容如下:
未认证授权的服务。
CAS的服务记录是空的,没有定义服务。希望通过CAS进行认证的应用程序必须在服务记录中明确定义
-
解决办法:
- 修改cas服务端http支持的配置文件,路径:
cas\WEB-INF\classes\services\HTTPSandIMAPS-10000001.json
。
{ "@class" : "org.apereo.cas.services.RegexRegisteredService", // "serviceId" : "^(https|imaps)://.*", "serviceId" : "^(https|http|imaps)://.*", "name" : "HTTPS and IMAPS", "id" : 10000001, "description" : "This service definition authorizes all application urls that support HTTPS and IMAPS protocols.", "evaluationOrder" : 10000 }
- CAS服务端启用记载JSON配置文件,在
cas\WEB-INF\classes\application.properties
添加如下配置:
cas.tgc.secure=false cas.serviceRegistry.initFromJson=true
- 修改cas服务端http支持的配置文件,路径:
修改后重启CSA服务端和客户端。
域名问题
- 从服务端验证之后,跳转回来时出错,内容如下:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching cas.example.org found
原因:由于配置CAS服务端使用HTTPS时,创建的证书中CN配置和域名不一致导致的。
-
解决办法:
- 重新创建证书:
keytool -genkey -alias cas -keyalg RSA -keysize 2048 -keypass changeit -storepass changeit -keystore casexample.keystore -dname "CN=cas.example.org,OU=casexample.com,O=casexample,L=casexample,ST=casexample,C=CN" -deststoretype pkcs12
- 将证书替换原来的证书。
重启CAS服务端和客户端。
PKIX path building failed
- 从服务端验证之后,跳转回来时出错,内容如下:
java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
原因:服务端的证书是不安全的,Cas的客户端在调用时因为安全提醒造成调用失败。CAS的客户端需要导入服务端的证书后,就正常了。
-
解决办法:
- 创建文件InstallCert.java,内容如下:
import java.io.*; import java.net.URL; // import java.security.*; import java.security.cert.*; // import javax.net.ssl.*; // public class InstallCert { // public static void main(String[] args) throws Exception { String host; int port; char[] passphrase; if ((args.length == 1) || (args.length == 2)) { String[] c = args[0].split(":"); host = c[0]; port = (c.length == 1) ? 443 : Integer.parseInt(c[1]); String p = (args.length == 1) ? "changeit" : args[1]; passphrase = p.toCharArray(); } else { System.out.println("Usage: java InstallCert <host>[:port] [passphrase]"); return; } // File file = new File("jssecacerts"); if (file.isFile() == false) { char SEP = File.separatorChar; File dir = new File(System.getProperty("java.home") + SEP + "lib" + SEP + "security"); file = new File(dir, "jssecacerts"); if (file.isFile() == false) { file = new File(dir, "cacerts"); } } System.out.println("Loading KeyStore " + file + "..."); InputStream in = new FileInputStream(file); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(in, passphrase); in.close(); // SSLContext context = SSLContext.getInstance("TLS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0]; SavingTrustManager tm = new SavingTrustManager(defaultTrustManager); context.init(null, new TrustManager[] {tm}, null); SSLSocketFactory factory = context.getSocketFactory(); // System.out.println("Opening connection to " + host + ":" + port + "..."); SSLSocket socket = (SSLSocket)factory.createSocket(host, port); socket.setSoTimeout(10000); try { System.out.println("Starting SSL handshake..."); socket.startHandshake(); socket.close(); System.out.println(); System.out.println("No errors, certificate is already trusted"); } catch (SSLException e) { System.out.println(); e.printStackTrace(System.out); } // X509Certificate[] chain = tm.chain; if (chain == null) { System.out.println("Could not obtain server certificate chain"); return; } // BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // System.out.println(); System.out.println("Server sent " + chain.length + " certificate(s):"); System.out.println(); MessageDigest sha1 = MessageDigest.getInstance("SHA1"); MessageDigest md5 = MessageDigest.getInstance("MD5"); for (int i = 0; i < chain.length; i++) { X509Certificate cert = chain[i]; System.out.println (" " + (i + 1) + " Subject " + cert.getSubjectDN()); System.out.println(" Issuer " + cert.getIssuerDN()); sha1.update(cert.getEncoded()); System.out.println(" sha1 " + toHexString(sha1.digest())); md5.update(cert.getEncoded()); System.out.println(" md5 " + toHexString(md5.digest())); System.out.println(); } // System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]"); String line = reader.readLine().trim(); int k; try { k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1; } catch (NumberFormatException e) { System.out.println("KeyStore not changed"); return; } // X509Certificate cert = chain[k]; String alias = host + "-" + (k + 1); ks.setCertificateEntry(alias, cert); // OutputStream out = new FileOutputStream("jssecacerts"); ks.store(out, passphrase); out.close(); // System.out.println(); System.out.println(cert); System.out.println(); System.out.println ("Added certificate to keystore 'jssecacerts' using alias '" + alias + "'"); } // private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray(); // private static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 3); for (int b : bytes) { b &= 0xff; sb.append(HEXDIGITS[b >> 4]); sb.append(HEXDIGITS[b & 15]); sb.append(' '); } return sb.toString(); } // private static class SavingTrustManager implements X509TrustManager { // private final X509TrustManager tm; private X509Certificate[] chain; // SavingTrustManager(X509TrustManager tm) { this.tm = tm; } // public X509Certificate[] getAcceptedIssuers() { //throw new UnsupportedOperationException(); return new X509Certificate[0]; } // public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { throw new UnsupportedOperationException(); } // public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { this.chain = chain; tm.checkServerTrusted(chain, authType); } } // }
编译InstallCert.java:
javac InstallCert.java
生成客户端证书:
java InstallCert cas.example.org:8443
。填写您的域名和端口,运行InstallCert。运行过程中,出现了错误提示后,根据提示输入1,命令就自动生成了证书安装证书到客户端JVM,将生成的文件jssecacerts复制到
%java_home%\jre\lib\security
目录下。
重启CAS服务端和客户端。