IdP认证对接方案4-企业微信
感谢首师大张刚刚老师的文档勘误
作为IdP对接ldap、oauth、CAS之后的第4种身份认证方式,“IdP+企业微信”对接方案适用于学校内部准备采用企业微信完成CARSI认证的情况。所采用IdP版本为3.4.7。具体对接工作包括:
- 学校在本校的企业微信中申请“CARSI服务”应用;
- 配置“CARSI服务”应用;
安装配置CARSI IdP;
- IdP运行测试。
1、申请企业微信应用“CARSI资源服务”
进入企业微信,应用管理,自建,选择创建应用。如果已经申请过应用,直接进入应用详情页面
创建完成后,进入应用详情,记录AgentId和Secret,后续IdP安装与配置需要用到这两个参数。
进入我的企业,获取企业ID。后续IdP安装与配置需要用到这个参数。
2、配置“CARSI资源共享”应用
进入应用详情,功能,将工作台应用主页修改成https://dspre.carsi.edu.cn/Shibboleth.sso/Login?SAMLDS=1&target=https%3A%2F%2Fdspre.carsi.edu.cn%2Fwxds&entityID=https%3A%2F%2F{SERVERNAME}%2Fidp%2Fshibboleth。
注意:请将{SERVERNAME}替换成IdP域名,如idp.xxx.edu.cn。
进入应用详情,开发者接口,企业微信授权登录,授权回调域名改成IdP域名,例如idp.xxx.edu.cn。
进入应用详情,开发者接口,网页授权及JS-SDK,设置改成IdP域名,例如idp.xxx.edu.cn。
3、安装配置CARSI IdP
3.1 准备IdP系统环境(CentOS8)
- 系统环境:CentOS 8 64bit 最小安装,内存≥4G,硬盘≥50G;
- IdP域名(网络中心维护,建议:idp.xxx.edu.cn;图书馆维护,建议:idp-lib.xxx.edu.cn),以及对应的https证书,域名一经确定,安装配置后无法修改;
- 网络可通达校园网外网,如果机器前面有防火墙,需要开通机器的TCP 80,443端口;
- 时间同步服务器,以ntp.aliyun.com为例,可根据校园网网络情况进行调整;
3.2 手动安装(CentOS8)
1. 基础配置(网络配置、修改主机名称、关闭selinux、配置时间同步)
#修改默认密码
[root@www ~]# passwd
#输入两次新密码
#配置网络
[root@www ~]# vi /etc/sysconfig/network-scripts/ifcfg-ens160
BOOTPROTO=static
ONBOOT=yes
IPADDR=IP地址
NETMASK=子网掩码
GATEWAY=默认网关
DNS1=DNS服务器
#修改
IPV6INIT=yes
IPV6_AUTOCONF=no
#新增
IPV6ADDR=IPv6地址,例如xxxx:xxxx:xxxx:xxxx::xxxx/64
IPV6_DEFAULTGW=IPv6网关,例如xxxx:xxxx:xxxx:xxxx::1
[root@www ~]# nmcli c reload
#修改主机名
[root@www ~]# vi /etc/hostname
#将localhost.localdomain改成主机域名,例如idp.xxx.xxx.xxx
[root@www ~]# hostname xxx.xxx.xxx.xxx
#修改hostname立即生效
#关闭SELinux
[root@www ~]#setenforce 0
#关闭开机启动SELinux
[root@www ~]# vi /etc/selinux/config
# line 7:修改为
SELINUX=disable
# 查看当前selinux状态
[root@www ~]# getenforce
Permissive #表示selinux已关闭
#配置时间同步
[root@www ~]# vi /etc/chrony.conf
#注释掉
#pool 2.centos.pool.ntp.org iburst
#新增时间同步服务器
pool ntp.aliyun.com iburst
#重启时间同步服务
[root@www ~]# systemctl restart chronyd
[root@www ~]# systemctl enable chronyd
#手动同步时间
[root@www ~]# chronyc -a makestep
200 OK #同步成功
#设置时区
[root@www ~]# timedatectl set-timezone Asia/Shanghai
#查看时间同步结果
[root@www ~]# timedatectl
Local time: Thu 2020-07-02 14:51:24 CST
Universal time: Thu 2020-07-02 06:51:24 UTC
RTC time: Thu 2020-07-02 06:51:23
Time zone: Asia/Shanghai (CST, +0800)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
2.开放本机端口
IdP本机开放80、443端口,443端口提供web服务。80端口用于某些HTTPS证书在更新时的连接性测试(如Let's Encrypt),可根据实际情况选择是否开启。
本机防火墙上开放相应端口(http和https分别对应80和443)
注意:8443端口在SAML1协议中使用,新版IdP和SP采用SAML2协议,可以停止SAML1协议的支持,无需开启8443端口
[root@www ~]# firewall-cmd --add-service=http --permanent [root@www ~]# firewall-cmd --add-service=https --permanent
刷新本机防火墙
[root@www ~]# firewall-cmd --reload
如果本机前面配置有其他防火墙,请联系防火墙管理员开通:外部服务器可访问本机80 、443端口(TCP端口)。
3.安装IdP运行环境
安装tomcat和nginx,tomcat是idp的运行容器,同时为了便于日志收集以及https证书配置,安装nginx提供web服务,用户直接访问nginx,nginx再将请求转发到tomcat,并返回该请求的响应结果。
1)安装JDK
[root@www ~]# dnf -y install java-11-openjdk java-11-openjdk-devel [root@www ~]# cat > /etc/profile.d/java.sh <<'EOF' export JAVA_HOME=$(dirname $(dirname $(readlink $(readlink $(which java))))) export PATH=$PATH:$JAVA_HOME/bin EOF [root@www ~]# source /etc/profile.d/java.sh [root@www ~]# java --version openjdk 11.0.5 2019-10-15 LTS OpenJDK Runtime Environment 18.9 (build 11.0.5+10-LTS) OpenJDK 64-Bit Server VM 18.9 (build 11.0.5+10-LTS, mixed mode, sharing)
2)安装配置Tomcat
[root@www ~]# curl -O https://downloads.apache.org/tomcat/tomcat-9/v9.0.39/bin/apache-tomcat-9.0.39.tar.gz
[root@www ~]# tar zxvf apache-tomcat-9.0.39.tar.gz
[root@www ~]# mv apache-tomcat-9.0.39 /usr/libexec/tomcat9
[root@www ~]# useradd -M -d /usr/libexec/tomcat9 tomcat
[root@www ~]# chown -R tomcat. /usr/libexec/tomcat9
[root@dlp ~]# vi /usr/lib/systemd/system/tomcat9.service
# create new
[Unit]
Description=Apache Tomcat 9
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/libexec/tomcat9/bin/startup.sh
ExecStop=/usr/libexec/tomcat9/bin/shutdown.sh
RemainAfterExit=yes
User=tomcat
Group=tomcat
[Install]
WantedBy=multi-user.target
[root@dlp ~]# systemctl enable --now tomcat9
#tomcat配置
#新建idp.xml
[root@www ~]# vi /usr/libexec/tomcat9/conf/Catalina/localhost/idp.xml
<Context docBase="/opt/shibboleth-idp/war/idp.war"
privileged="true"
antiResourceLocking="false"
antiJARLocking="false"
unpackWAR="false"
swallowOutput="true" />
[root@www ~]# vi /usr/libexec/tomcat9/conf/server.xml
#在倒数第3行</Engine>前面,增加下述配置。从而将传递给应用的客户端ip和请求协议替换为X-Forwarded-For和X-Forwarded-Proto中的值。
<Valve className="org.apache.catalina.valves.RemoteIpValve"
internalProxies="127.0.0.1|0:0:0:0:0:0:0:1"
remoteIpHeader="x-forwarded-for"
protocolHeader="x-forwarded-proto"
/>
3)安装配置Nginx
[root@www ~]# dnf -y install nginx
[root@www ~]# vi /etc/nginx/nginx.conf
# line 41: change to your hostname
server_name www.srv.world;
#配置http自动跳转至https
在listen [::]:80 default_server;后加上
return 301 https://$host$request_uri;
#将默认的https配置部分取消注释,其中/etc/nginx/fullchain.pem请替换成证书的绝对路径,/etc/nginx/privkey.pem请替换成证书key的绝对路径
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name idp.xxx.edu.cn;
root /usr/share/nginx/html;
ssl_certificate "/etc/nginx/fullchain.pem";
ssl_certificate_key "/etc/nginx/privkey.pem";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers PROFILE=SYSTEM;
ssl_prefer_server_ciphers on;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
[root@www ~]# systemctl enable --now nginx
#新建idp.xml
[root@www ~]# vi /etc/nginx/nginx.conf
#在server标签里面新增
location /idp {
proxy_pass http://localhost:8080/idp;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
4. 安装配置IdP
1)安装IdP包
[root@www ~]# curl -O https://shibboleth.net/downloads/identity-provider/3.4.7/shibboleth-identity-provider-3.4.7.tar.gz [root@www ~]# tar zxvf shibboleth-identity-provider-3.4.7.tar.gz [root@www ~]# cd shibboleth-identity-provider-3.4.7 [root@www ~]# ./bin/install.sh Source (Distribution) Directory (press <enter> to accept default): [/root/inst/shibboleth-identity-provider-3.x.x] #默认回车 Installation Directory: [/opt/shibboleth-idp] #默认回车 Hostname: [idp.xxx.edu.cn] enter #确认是修改后的域名,无误后回车 SAML EntityID: [https://域名/idp/shibboleth] #默认回车 Attribute Scope: [xxx.edu.cn] #输入学校域名,如xxx.edu.cn 回车 Backchannel PKCS12 Password: #创建后台证书密码 Re-enter password: #再输入一遍 Cookie Encryption Key Password: #创建Cookie加密密码 Re-enter password: #再输入一遍 Warning: /opt/shibboleth-idp/bin does not exist. Warning: /opt/shibboleth-idp/dist does not exist. Warning: /opt/shibboleth-idp/doc does not exist. Warning: /opt/shibboleth-idp/system does not exist. Warning: /opt/shibboleth-idp/webapp does not exist. Generating Signing Key, CN = 域名 URI = https://域名/idp/shibboleth ... ...done Creating Encryption Key, CN = 域名 = https://域名/idp/shibboleth ... ...done Creating Backchannel keystore, CN = 域名 URI = https://域名/idp/shibboleth ... ...done Creating cookie encryption key files... ...done Rebuilding /opt/shibboleth-idp/war/idp.war ... ...done BUILD SUCCESSFUL #安装成功
2)配置IdP
Tomcat 默认没有提供 Java Server Tag Library,这使得 IdP3 的 status 页面无法显示。解决的办法是下载 jstl的jar包,然后放在/opt/shibboleth-idp/edit-webapp/WEB-INF/lib/ 内,然后需要重新 Build 一下 idp。在 idp.home 的目录下,./bin/build.sh 即可
将no-conversation-state.rar解压缩后的no-conversation-state.jsp放到/opt/shibboleth-idp/edit-webapp里面,将json-20200518.jar、shib-cas-authenticator-3.3.0.jar和cas-client-core-3.6.0.jar放到/opt/shibboleth-idp/edit-webapp/WEB-INF/lib目录下,将web.rar解压缩后的web.xml放到/opt/shibboleth-idp/edit-webapp/WEB-INF/下
[root@www ~]# cd /opt/shibboleth-idp/edit-webapp/WEB-INF/lib/ [root@www ~]# curl -O https://build.shibboleth.net/nexus/service/local/repositories/thirdparty/content/javax/servlet/jstl/1.2/jstl-1.2.jar [root@www ~]# cd /opt/shibboleth-idp/bin [root@www ~]# ./build.sh Installation Directory: [/opt/shibboleth-idp] #回车 Rebuilding /opt/shibboleth-idp/war/idp.war ... ...done BUILD SUCCESSFUL
更新idp.properties
[root@www ~]# vi /opt/shibboleth-idp/conf/idp.properties
#修改
idp.authn.flows=External
#新增,将{APPID}替换成应用的secret,将{APPSECRET}替换成企业ID,将{AgentID}替换成应用的agentid,将{SERVERNAME}替换成idp的域名
shibcas.oauth2UrlPrefix = https://open.weixin.qq.com/connect/oauth2/authorize
shibcas.oauth2LoginUrl = ${shibcas.oauth2UrlPrefix}?appid={APPSECRET}&response_type=code&scope=snsapi_base&state=STATE
shibcas.oauth2LoginUrlh5 = https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid={APPSECRET}&agentid={AgentID}&state=STATE
shibcas.serverName = https://{SERVERNAME}
shibcas.oauth2TokenUrl = https://qyapi.weixin.qq.com/cgi-bin/gettoken
shibcas.oauth2ResourceUrl = https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo
shibcas.oauth2GetUserUrl = https://qyapi.weixin.qq.com/cgi-bin/user/get
shibcas.oauth2clientid = {APPSECRET}
shibcas.oauth2clientsecret = {APPID}
shibcas.oauth2redirecturi = https%3a%2f%2f{SERVERNAME}%2fidp%2fAuthn%2fExternal%3fconversation%3de1s1
shibcas.getdepartmentUrl = https://qyapi.weixin.qq.com/cgi-bin/department/list
2.1)属性定义
配置属性释放,用以下内容替换/opt/shibboleth-idp/conf/attribute-resolver.xml文件。
修改<AttributeDefinition xsi:type="ScriptedAttribute" id="eduPersonScopedAffiliation">中的<Script>部分,根据position的实际取值进行映射的调整。关于身份属性取值,需要将本地用户身份的取值,对应到CARSI联盟标准取值,包括:faculty(教师),student(学生),staff(教工),employee(雇员),member(各类人员,包括faculty、student、staff、employee),alum(校友),affiliate(附属人员或临聘,常用),other(CARSI补充,不建议优先使用)。建议配置时尽可能细化用户身份分类,避免后期修改配置。
注意:默认使用企业微信的position表示用户身份。
<?xml version="1.0" encoding="UTF-8"?>
<AttributeResolver
xmlns="urn:mace:shibboleth:2.0:resolver"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd">
<!-- ========================================== -->
<!-- Attribute Definitions -->
<!-- ========================================== -->
<AttributeDefinition xsi:type="ScriptedAttribute" id="eduPersonScopedAffiliation">
<Dependency ref="position" />
<Script><![CDATA[
var localpart = "";
if(typeof(position)=="undefined"){
localpart = "member";
}else{
if(position.getValues().get(0)=="staf") localpart = "staff";
else if(position.getValues().get(0)=="std") localpart = "student";
else localpart = "member";
}
eduPersonScopedAffiliation.addValue(localpart + "@%{idp.scope}");
]]></Script>
<AttributeEncoder xsi:type="SAML1String" name="urn:mace:dir:attribute-def:eduPersonScopedAffiliation" encodeType="false" />
<AttributeEncoder xsi:type="SAML2String" name="urn:oid:1.3.6.1.4.1.5923.1.1.1.9" friendlyName="eduPersonScopedAffiliation" encodeType="false" />
</AttributeDefinition>
<AttributeDefinition xsi:type="SubjectDerivedAttribute" id="position" principalAttributeName="position"></AttributeDefinition>
<AttributeDefinition xsi:type="Scoped" id="eduPersonPrincipalName" scope="%{idp.scope}">
<InputAttributeDefinition ref="uid" />
<AttributeEncoder xsi:type="SAML1ScopedString" name="urn:mace:dir:attribute-def:eduPersonPrincipalName" encodeType="false" />
<AttributeEncoder xsi:type="SAML2ScopedString" name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" friendlyName="eduPersonPrincipalName" encodeType="false" />
</AttributeDefinition>
<AttributeDefinition id="uid" xsi:type="PrincipalName">
<AttributeEncoder xsi:type="SAML1String" name="urn:mace:dir:attribute-def:uid" encodeType="false" />
<AttributeEncoder xsi:type="SAML2String" name="urn:oid:0.9.2342.19200300.100.1.1" friendlyName="uid" encodeType="false" />
</AttributeDefinition>
<AttributeDefinition id="eduPersonTargetedID" xsi:type="SAML2NameID" nameIdFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">
<InputDataConnector ref="ComputedIDConnector" attributeNames="computedID"/>
<AttributeEncoder xsi:type="SAML1XMLObject" name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" encodeType="false"/>
<AttributeEncoder xsi:type="SAML2XMLObject" name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" friendlyName="eduPersonTargetedID" encodeType="false"/>
</AttributeDefinition>
<AttributeDefinition id="eduPersonEntitlement" xsi:type="Simple">
<InputDataConnector ref="staticAttributes" attributeNames="eduPersonEntitlement" />
<AttributeEncoder xsi:type="SAML1String" name="urn:mace:dir:attribute-def:eduPersonEntitlement" encodeType="false"/>
<AttributeEncoder xsi:type="SAML2String" name="urn:oid:1.3.6.1.4.1.5923.1.1.1.7" friendlyName="eduPersonEntitlement" encodeType="false"/>
</AttributeDefinition>
<DataConnector id="ComputedIDConnector" xsi:type="ComputedId" generatedAttributeID="computedID" salt="xxxxxxxxxxxxxxxxxxxx" encoding="BASE64">
<InputAttributeDefinition ref="eduPersonPrincipalName" />
</DataConnector>
<DataConnector id="staticAttributes" xsi:type="Static">
<Attribute id="eduPersonEntitlement">
<Value>urn:mace:dir:entitlement:common-lib-terms</Value>
</Attribute>
</DataConnector>
</AttributeResolver>
2.2)释放用户属性
2.3)IdP隐私保护配置
2.4)Metadata配置
下载https://dspre.carsi.edu.cn/carsifed-metadata-pre.xml 文件,放入/opt/shibboleth-idp/metadata文件夹,并且修改文件的所属用户和组。
[root@www ~]# chown -R tomcat.tomcat /opt/shibboleth-idp
将联盟提供的metadata验证证书dsmeta.pem放入/opt/shibboleth-idp/credentials目录下。修改metadata-providers.xml,maxRefreshDelay="PT10M"表示metadata最长更新时间10分钟。
[root@www ~]# vi /opt/shibboleth-idp/conf/metadata-providers.xml
#在</MetadataProvider>内新增
<MetadataProvider id="HTTPMetadata"
xsi:type="FileBackedHTTPMetadataProvider"
backingFile="/opt/shibboleth-idp/metadata/carsifed-metadata-pre.xml"
minRefreshDelay="PT5M"
maxRefreshDelay="PT10M"
metadataURL="https://dspre.carsi.edu.cn/carsifed-metadata-pre.xml">
<MetadataFilter xsi:type="SignatureValidation" certificateFile="/opt/shibboleth-idp/credentials/dsmeta.pem" />
<MetadataFilter xsi:type="EntityRoleWhiteList">
<RetainedRole>md:SPSSODescriptor</RetainedRole>
</MetadataFilter>
</MetadataProvider>
重启tomcat和apache
[root@www ~]# chown -R tomcat.tomcat /opt/shibboleth-idp #启动tomcat和apache [root@www ~]# systemctl restart tomcat9 [root@www ~]# systemctl restart nginx
2.5)日志功能
[root@www ~]# vi /opt/shibboleth-idp/conf/audit.xml
#line 18 替换
<entry key="Shibboleth-Audit" value="%T|%b|%I|%SP|%P|%IdP|%bb|%III|%u|%ac|%attr|%n|%i|%a|%s|" />
#取消注释
<bean id="shibboleth.AuditDateTimeFormat" class="java.lang.String" c:_0="YYYY-MM-dd'T'HH:mm:ss.SSSZZ" />
<util:constant id="shibboleth.AuditDefaultTimeZone" static-field="java.lang.Boolean.TRUE" />
[root@www ~]# mkdir /usr/share/nginx/html/auditlog
[root@www ~]# vi /etc/nginx/nginx.conf
#在location /idp前面增加
location /auditlog {
allow 115.27.243.6;
deny all;
}
#新建
[root@www ~]# vi /usr/share/nginx/html/auditlog/auditlog.sh
rm -rf /usr/share/nginx/html/auditlog/auditlog-`date -d -24hours +%Y-%m-%d-%H`.log
grep `date -d -1hours +%Y-%m-%dT%H` /opt/shibboleth-idp/logs/idp-audit.log > /usr/share/nginx/html/auditlog/auditlog-`date -d -1hours +%Y-%m-%d-%H`.log
#添加定时任务
[root@www ~]# crontab -e
0 */1 * * * sh /usr/share/nginx/html/auditlog/auditlog.sh >/dev/null 2>&1
#重启tomcat和apache
[root@www ~]# systemctl restart tomcat9
[root@www ~]# systemctl restart nginx
4、IdP运行测试
1)向CARSI联盟提交IdP配置信息(上传IdP Metadata)
将/opt/shibboleth-idp/metadata/idp-metadata.xml文件下载到本地。
登陆 CARSI会员自服务系统 用户名为申请时填的学校域名,密码为申请时填的项目负责人的手机号。
在“我的CARSI→我的IdP”中,选择“上传Metadata”完成该文件的上传,上传成功后该页面会显示“已提供”。
2)PC端测试步骤
3)企业微信端测试
版权所有©北京大学计算中心