基于SAML2协议改造exchange owa登录

exchange自带owa登录,ad账号密码是必填项。登录方式单一,不能和企业内SSO系统融合,用户忘记密码、密码过期等会带来很多不便

目标是实现多种方式登录exchange owa,例如微信扫码,短信验证码,OTP,接入外部单点登录等。首先要解决登录exchange owa必须要使用ad账号密码这个问题。

这里参考了 小米使用adfs+cas的解决思路 ,我们使用adfs+saml2协议来实现

具体实现

1、接入ADFS登录

exchange owa接入ADFS登录可以参考 微软官方文档,官网描述的步骤很详细,按照一步一步操作即可完成接入。

接入后可以使用adfs自带的登录完成exchange owa登录认证,此时我们已经实现了替换exchange owa自带的登录

但是还是没有摆脱必须输入ad账号密码的步骤

2、使用pysaml2库实现saml2协议

参考小米的adfs+cas的解决思路,cas github 大概了解了下cas的功能,ADFS作为cas的SP,cas作为ADFS的IDP,cas配置为ADFS的“声明提供方”,cas使用saml2协议完成ADFS的接入。

但是cas作为比较成熟的解决方案,本身还是比较“重”的,我们仅仅需要一个saml2协议的实现,并不需要一整套cas系统

在github里搜索到了一个库,pysaml2 github地址 ,是python实现的saml2协议的库。这个库自带了一个非常简单的示例,让我们可以用一条命令运行IDP,文档地址

如果你看到和我一样的提示,说明运行成功了

[root@ityw-centos-vdi idp2]# python idp.py idp_conf
[2021-06-11 01:07:11,388] [DEBUG] [saml2.assertion.__init__] policy restrictions: None
[2021-06-11 01:07:11,389] [DEBUG] [saml2.assertion.__init__] policy restrictions: None
[2021-06-11 01:07:11,389] [DEBUG] [saml2.assertion.__init__] policy restrictions: {'default': {'lifetime': {'minutes': 15}, 'attribute_restrictions': None, 'name_form': 'urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified', 'entity_categories': None}}
[2021-06-11 01:07:11,427] [INFO] [saml2.idp.<module>] Server starting
IDP listening on localhost:8088

要将我们的IDP接入adfs,要进行一些配置。

pki 目录下的 mycert.pem 和 mykey.pem 文件,分别对应我们证书的.crt和.key,要将我们自己的证书内容覆盖上去

pysaml2-master\tools 目录下的 make_metadata.py 文件复制到 pysaml2-master\example\idp2 目录里

idp.py 文件里的 PASSWD 配置是账号和密码,我们新增一个 test01 账号,密码设置的和AD密码不一致

PASSWD = {
    "test01": "test01",
}

pysaml2-master\example\attributemaps 目录复制到 pysaml2-master\example\idp2 目录下

idp_conf.py 文件

我们新增一条导入

from saml2.xmldsig import SIG_RSA_SHA256, DIGEST_SHA256

HOST ,我们配置下idp的host地址(要在DNS做对应A记录)

HOST = 'saml.testyunwei.com'

CONFIG.service.idp.policy.default.name_form 值改为

"name_form": "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"

CONFIG.service.idp.policy.default.entity_categories 字段删除

CONFIG.service.idp.name_id_format 值改为

`"name_id_format": ["urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"]

CONFIG.service.idp 新增四个值

"sign_assertion": True,
"sign_response": True,
'signing_algorithm': SIG_RSA_SHA256,
'digest_algorithm': DIGEST_SHA256,

CONFIG.metadata.local 值改为

"local": [full_path("pki/sp.xml")]

CONFIG.attribute_map_dir 取消注释,并且值改为

"attribute_map_dir": "./attributemaps"

idp_user.py 文件我们新增一个users用户信息

USERS = {
    "test01": {
        "upn": "test01@testyunwei.com"
    },
}

我们访问 ADFS的sp终结点获取sp.xml 文件

https://adfs.testyunwei.com/FederationMetadata/2007-06/FederationMetadata.xml

把下载下来的xml文件重命名为sp.xml 复制到 pysaml2-master\example\idp2 目录下

这时,我们再重新运行IDP

python make_metadata.py idp_conf.py > idp.xml
python idp.py idp_conf

看到还是刚才的运行成功的记录,只不过监听host变了

[root@ityw-centos-vdi idp2]# python idp.py idp_conf
[2021-06-11 02:00:49,005] [DEBUG] [saml2.assertion.__init__] policy restrictions: None
[2021-06-11 02:00:49,005] [DEBUG] [saml2.assertion.__init__] policy restrictions: None
[2021-06-11 02:00:49,005] [DEBUG] [saml2.assertion.__init__] policy restrictions: {'default': {'lifetime': {'minutes': 15}, 'attribute_restrictions': None, 'name_form': 'urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified', 'entity_categories': None}}
[2021-06-11 02:00:49,043] [INFO] [saml2.idp.<module>] Server starting
IDP listening on saml.testyunwei.com:8088

我们在ADFS上添加一个声明提供方,从url导入idp元数据:https://saml.testyunwei.com:8088/idp.xml,然后无脑下一步即可,中间有警告可以忽略。

我们配置owa和ecp的依赖方信任,还有我们刚才新增的声明提供方信任,都需要配置声明规则完成转换,我们只用upn一个属性就可以定位到具体用户

配置完成后我们的IDP就已经实现了,此时我们可以选择使用IDP登录,并且用的不再是AD账号密码,而是我们刚才配置的用户upn和PASSWD里的密码,如下图可以看到,使用ADFS自带的ad账号密码登录提示密码错误,但是使用IDP可以成功登录OWA了

后记

到这里dome基本已经实现,认证体系由IDP实现,脱离了ad账号密码完成exchange owa登录

下篇研究下 pysaml2 原理

pysaml2深入研究