IT技术博客大学习 共学习 共进步

Apache + Jetty 架设 CAS 单点登录

无知的我 2009-11-12 22:56:07 浏览 5,063 次

最近一段时间一直在断断续续地尝试 CAS 单点登录的问题,一般的文章,都是直接使用 Tomcat 或者 Jetty 等 Java 应用服务器直接配置 SSL 并安装 CAS 的,但我不太想让 Java 服务器直接 binding 到 443 端口,因此就想仍然用 Apache 处理 SSL 请求,并转发给 Jetty。在这个过程中,主要尝试了以下个问题:

  1. 如何生成自签名的证书
  2. 如何配置 Apache
  3. 如何配置 Jetty
  4. 安装、测试 CAS
  5. 把自己的 CA 证书导入到 Java 的 cacerts 文件中并测试 CAS Proxy

整个过程在 Ubuntu 7.10 上完成,现记录如下。

1. 生成自签名的证书

通常要配置 https 的服务器,都需要一个由正式的 CA 机构认证的 X509 证书。当客户端连接 https 服务器时,会通过 CA 的共钥来检查这个证书的正确性。但要获得 CA 的证书是一件很麻烦的事情,而且还要花费一定的费用。因此通常一些小的机构会是使用自签名的证书。也就是自己做 CA,给自己的服务器证书签名。

这个过程有两个主要的步骤,首先是生成自己的 CA 证书,然后再生成各个服务器的证书并为它们签名。 我是用 OpenSSL 来生成自签名证书的。

第一步是制作 CA 的证书:

以下是引用片段:
openssl genrsa -des3 -out my-ca.key 2048

openssl req -new -x509 -days 3650 -key my-ca.key -out my-ca.crt

这会生成 my-ca.key 和 my-ca.crt 文件,前者存放着使用 my-ca.crt 制作签名时必须的密钥,应当妥善保管。而后者是可以公开的。上面的命令为 my-ca.key 设定的有效期为 10 年。

用命令

以下是引用片段:
openssl x509 -in my-ca.crt -text -noout

可以查看 my-ca.crt 文件的内容。

有了 CA 证书之后,就可以为自己的服务器生成证书了:

以下是引用片段:
openssl genrsa -des3 -out mars-server.key 1024

openssl req -new -key mars-server.key -out mars-server.csr

openssl x509 -req -in mars-server.csr -out mars-server.crt -sha1 -CA my-ca.crt -CAkey my-ca.key -CAcreateserial -days 3650

前两个命令会生成 key、csr 文件,最后一个命令则通过 my-ca.crt 为 mars-server.csr 制作了 x509 的签名证书。

需要注意的是,在执行上述第二个命令时,Common Name 选项应当输入的是服务器的域名,否则在用户通过 https 协议访问时每次都会有额外的提示信息。

用命令

以下是引用片段:
openssl x509 -in mars-server.crt -text -noout

可以查看 mars-server.crt 文件的内容。

2. 配置 Apache 服务器

首先,创建 /etc/apache2/ssl 目录,将刚刚制作的 my-ca.crt、mars-server.key 和 mars-server.crt 文件拷贝到这个目录中。

接着执行命令

以下是引用片段:
a2emod ssl

激活 Apache 的 SSL 模块,然后在 /etc/apache2/sites-enable/ 中添加虚拟主机,这个过程与添加普通的虚拟主机类似,不同点在于该主机的端口应为 443。配置如下:

以下是引用片段:
NameVirtualHost *:443
<VirtualHost *:443>
  ServerName localhost

  DocumentRoot /var/www

SSLEngine On

  SSLCipherSuite HIGH:MEDIUM

  SSLProtocol all -SSLv2

  SSLCertificateFile /etc/apache2/ssl/mars-server.crt

  SSLCertificateKeyFile /etc/apache2/ssl/mars-server.key

  SSLCACertificateFile /etc/apache2/ssl/my-ca.crt
  <Directory /var/www>
    Order deny,allow
    Allow from localhost

</Directory>

</VirtualHost>

<VirtualHost *:80>

ServerName localhost

  DocumentRoot /var/www

<Directory /var/www>    Order deny,allow

    Allow from localhost

</Directory>

</VirtualHost>

以上配置保证了用户在访问 443 和 80 端口时可以看到相同的内容,而仅仅是使用的协议不同。修改好配置后,便可以重启 Apache 服务器,这时需要输入 mars-server.key 的密码。用浏览器访问

以下是引用片段:
https://localhost/

这时应当看到一个弹出对话框,让你确认是否信任该站点的证书,选择信任后,便可以查看该站点的内容了。

由于大多数 Apache 服务器都是在服务器启动时自动启动,为了避免在启动 Apache 时输入密码,可以用以下命令生成不加密的 mars-server.key 文件:

以下是引用片段:
openssl rsa -in mars-server.key -out mars-server.key.insecure

用新生成的 mars-server.key.insecure 代替原有的 key 文件即可。

3. 配置 Jetty

Jetty 是一个很容易配置的 Java Servlet/JSP 服务器,下载解压后,用命令

以下是引用片段:
java -jar start.jar

即可执行。

由于我们希望通过 Apache 来访问 Jetty,就要激活 Jetty 对 AJP 的支持。可以用如下命令来启动服务器:

以下是引用片段:
java -jar start.jar etc/jetty.xml etc/jetty-ajp.xml

在 Apache 这一端,首先要安装 mod-jk 模块并激活它

以下是引用片段:
apt-get install libapache2-mod-jk

a2emod jk

其次要编写一个 /etc/apache2/worker.properties 文件,描述一下刚刚配置好的 jetty 服务器,文件内容如下:

以下是引用片段:
worker.list=jetty

worker.jetty.port=8009

worker.jetty.host=127.0.0.1

worker.jetty.type=ajp13

worker.jetty.lbfactor=1

接着要编写一个 /etc/apache2/mods-enabled/jk.conf 文件,内容如下:

以下是引用片段:
<IfModule mod_jk.c>
  JkWorkersFile "/etc/apache2/worker.properties"

  JkLogFile "/var/log/apache2/mod_jk.log"

  JkLogLevel info

  JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "

  JkOptions +ForwardKeySize +ForwardURICompat
</IfModule>

最后,要修改刚刚的那个配置文件,让 mod_jk 来处理发送给 /cas/* 的请求,在虚拟主机的配置中加入如下命令:

以下是引用片段:
JkMount /cas/* jetty

4. 安装、测试 CAS

下载 CAS 3.x,并将 /modules/cas-server-webapp-*.war 文件复制到 jetty 的 webapps 目录下,改名为 cas.war。

此时通过浏览器访问 https://localhost/cas/ 便可看到 CAS 的界面了。我们是使用 LDAP 服务器来存储用户信息的,关于 CAS 的定制问题,稍后在其它的文章中再阐述。

我是通过 phpCAS 来对 CAS 服务器进行测试的,首先下载 phpCAS-0.6*、解压到 /var/www/phpcas 目录中。

安装 php-curl 和 php-pear,并通过 pear 安装 PEAR::DB。

以下是引用片段:
pear install DB

将 phpcas/docs/examples/ 中的文件复制到 phpcas/sources/ 目录中,修改这些文件中相关的 URL 信息,并用浏览器访问 example_simple.php,便可看到 CAS 的登录界面了。输入用户名密码后,应当可以看到登录成功的信息。

5. 将 my-ca.crt 导入到 Java 的 cacerts 文件中,并测试 CAS Proxy

CAS Proxy 的作用是让一个 CAS 的应用可以通过 CAS 来访问另一个 CAS 应用,而不需要用户多次提供密码。在这种情况下,CAS 会通过 https 访问每个 CAS 应用。由于我们的 CA 证书是自己制作的,它并不存在于 Java 的根证书列表中,这就导致 CAS 无法正常地连接我们的 https 服务器从而导致 CAS Proxy 功能不可用。要解决这个问题,必须将 my-ca.crt 文件导入到 Java 的根证书列表中。

我尝试了用 Java 提供的 keytool 来处理这个问题,但它总是要求输入 cacerts 文件的密码,而我根本没有这个密码。后来尝试用 IBM 的 keyman 解决了这个问题。keyman 是一个 GUI 程序,下载后用它来编辑 /etc/java-6-sun/security/cacerts 文件即可。注意导入密钥时,应选则 trustcacerts。

导入该密钥后,重启 Jetty 服务器,再访问 example_proxy.php 文件便可得到正确的结果了。

参考文献:

1. Van’s Apache SSL/TLS mini-HOWTO
2. Creating a self-signed SSL certificate
3. How to configure Apache SSL
4. Apache AJP13, mod_jk and mod_proxy_ajp
5. IBM KeyMan

建议继续学习

  1. Netty和Jetty的Java NIO 网络框架模型分析 (阅读 5,464)
  2. 互联网上的单点登录研究 (阅读 5,021)
  3. Jetty线程“互锁”导致数据传输性能降低问题分析 (阅读 4,323)
  4. 关于 Jetty Continuation (阅读 3,426)
  5. 【译】无附加模块实现Drupal的多子域名下的单点登录 (阅读 3,341)
  6. Jetty 8长连接上的又一个坑 (阅读 2,362)