自定义接口配置V1
此版本接口原配置可继续使用,新建请使用V2版本。
分为配置和开发两步,需要按照BDP的要求开发或修改IDP的两个接口,用于和BDP完成单点登录操作。
1 接口配置
整体配置信息与SAML2.0相似,不同的是需要先完成配置才能获取加密证书(pub_key),将证书应用到接口中才能完成配置。
1.1 IDP信息
自定义配置只需要提供统一登录和登出两个接口,接口需要按照 2 接口开发 的要求接收参数和返回结果值。
如果暂无接口,如需要重新开发接口,请先任意填写两个接口,完成配置才能获取到加密证书。
1.2 匹配用户信息
登录BDP需要使用BDP的用户信息,因此须将IDP中的用户信息与BDP中进行匹配,目前支持匹配BDP的登录账户名。
- 登录账户:IDP返回的用户信息中与BDP登录账户一致的字段,该字段应为用户的唯一标识,不能重复,如下图将IDP的“username”字段和BDP的登录账号匹配。
1.3 登出设置
开启后,退出BDP时会同时会请求IDP配置中填写的你的SSO服务登出接口,申请在IDP中退出账号信息,保持BDP与IDP两端的账号状态一致性。
不开启时,IDP配置中的登出接口无效,可随意填写。
1.4 加密方式
支持两种算法RSA与自定义,RSA主要用于Python语言,自定义适用于所有支持MD5的语言,具有更好的通用性。加密使用方式见下方代码示例。
1.5 SP信息
用于自定义IDP接口与BDP通信,均由BDP提供,请将以下信息复制粘贴至IDP服务器的配置中或在外部系统中调用:
配置项 | 必要/可选 | 说明 |
---|---|---|
audience | 必要 | SP的标识信息 |
sso | 必要 | BDP的单点登录入口,用于客户通过该接口免密登录,建议作为内部门户的登录链接 |
acs | 必要 | BDP的登录断言的接收服务,用于接收IDP认证后返回的用户信息 |
slo | 可选 | BDP的单点登出服务,IDP处用户退出时,可调用该接口通知BDP退出登录状态,保持状态一致 |
sls | 可选 | BDP的退出接口,区别与slo仅退出BDP,调用sls时将先退出IDP后再退出BDP |
pub_key | 必要 | 用户信息的加密证书。保存后再次进入编辑时可见,首次进入时没有。 |
1.6 登录验证
完成上述配置后,点击“保存”,此时设置还未完成,仅为保存设置,需要拿到认证证书并应用到自定义IDP接口中后生效。此时保存弹窗的验证链接无效。
获取认证证书并应用后再次保存,完成配置,须通过下方验证链接确认配置有效性;验证链接为上述步骤3中的SSO地址,点击链接或新建浏览器标签页复制链接,如果配置生效页面会向IDP进行验证,未登录时进入IDP的登录页,而不是BDP的登录页;登录后应跳转进入BDP。
获取验证链接:
- 保存时,会提示出验证链接,点击链接使用
- 保存后,可在添加列表的“操作”中点击的“验证”
2 接口开发
开发至少一个IDP登录验证(idp_login)接口,用于校验用户在IDP(通常为企业内部账号中心)的登录状态,并返回用户信息给BDP。
2.1 接口流程
登录:
- 用户通过内部系统访问BDP,调用BDP提供的SSO接口,传入domain;
- SSO接口回调(302重定向跳转)用户系统的idp_login接口,请求校验当前用户的登录状态;
- idp_login接口验证用户登录状态,验证通过后回调(302重定向跳转)BDP的acs接口,传入domain和user_info(user_info字符串加密处理)信息;
- BDP通过acs接口读取user_info(解密),映射到BDP的用户并登入系统;
退出(仅私有云):
- 用户在BDP退出时,调用BDP的slo接口;
- slo回调用用户系统的idp_logout接口;
- idp_logout接口退出成功后,回调BDP的sls接口;
- sls接口完成退出BDP;
2.2 登录验证接口
用于接收SP(BDP)的身份验证请求,验证当前用户是否在IDP中登录并返回用户信息返回给BDP,其中user_info需要对称加密。
IDP中判断登录结果:
- 未登录:跳转至IDP的登录页。
- 已登录:调用IDP的ACS接口,包含将两个请求参数。
请求参数说明:
参数名称 | 参数类型 | 是否必填 | 默认值 | 参数描述 | 最大长度 |
---|---|---|---|---|---|
domain | string | 必填 | 无 | BDP企业域 | 无 |
RelayState | string | 可选 | 无 | 验证后跳转链接由BDP提供 | 无 |
用户信息加密:
- 用户信息中须包含此前在开发者中心设置的登录账户对应字段,如使用username与BDP的登录名绑定时,用户信息中携带
username
参数 - user_info = json.dumps(user_info) 将字段转成字符串
- 利用在BDP配置custom_sso生成的公钥,将字符串user_info 加密,rsa.decrypt(user_info, pub_key)
- 加密后的字符串转Base64或MD5编码
- Base64编码或MD5转UrlEncode编码后传参
- 下附Python与Java的代码示例
Python——RSA的Base64加密接口示例:
import rsa
import json
import base64
from urllib import urlencode
pub_str = '''-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAIv7BNJT2ET7TVB1iYrxm4AdCf7xXoixFq38MdlL/W4l3Z5E+6Slo3Wu
9tXv9jQtfr0aHLTzMD3oxuBKKJ20IGx4KzdvlVZfkrutyc2pOen9L5CrnKXLbSdr
j7cGcZx2FBeBI9OvFmBBwig+NTgR/ybyMh5fwrnhENHwXPIOb62NAgMBAAE=
-----END RSA PUBLIC KEY-----
'''
user_info = {"username": "admin"}
user_info_str = json.dumps(user_info)
pub_key = rsa.PublicKey.load_pkcs1(pub_str)
cry = base64.encodestring(rsa.encrypt(user_info_str,pub_key ))
print cry
payload = urlencode({"user_info": cry})
print payload
Python——自定义加密(MD5)接口示例:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import md5
from urllib import urlencode
import json
def get_token(username, pub_key):
m1 = md5.new()
m1.update(username + pub_key.replace("\n", ""))
return m1.hexdigest()
pub_key = '''-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMr0CpVULys1pMkugjXvCSsSsX0CvpGxVQVgB/JFuOUHTTHErzOVbw8H
09e0l/IIG4jz2A1UydC4wXZCsLK6Wg5UdlfbBMhavmvHTwqsXSWxvAl5pi0r52G3
sBYGQ4q4Uo/cZC2BAl22fSaY1nKVxGaQLOinRaR34HDXM967hWNlAgMBAAE=
-----END RSA PUBLIC KEY-----
'''
user_info = {"username": "BDP_USER"}
token = get_token(user_info['username'], pub_key)
payload = urlencode({"user_info": json.dumps(user_info), "token": token, "domain": "domain"})
print payload
Java——自定义加密(MD5)接口示例:
package com.haizhi.script;
import org.json.JSONStringer;
import java.security.*;
import java.io.*;
import java.util.*;
import java.net.*;
public class UrlParse {
private String pub_key = "-----BEGIN RSA PUBLIC KEY-----\n" +
"MIGJAoGBAMr0CpVULys1pMkugjXvCSsSsX0CvpGxVQVgB/JFuOUHTTHErzOVbw8H\n" +
"09e0l/IIG4jz2A1UydC4wXZCsLK6Wg5UdlfbBMhavmvHTwqsXSWxvAl5pi0r52G3\n" +
"sBYGQ4q4Uo/cZC2BAl22fSaY1nKVxGaQLOinRaR34HDXM967hWNlAgMBAAE=\n" +
"-----END RSA PUBLIC KEY-----";
private String username = "test";
private String domain = "test";
public static void main(String args[]) {
UrlParse t = new UrlParse();
System.out.println(t.getUrlParse());
}
public String getUrlParse(){
Map<String, String> params = new HashMap<String, String>();
String user_info = getUserInfo(username);
String info = username + pub_key.replace("\n", "");
String token = UrlParse.getMD5(info);
params.put("user_info", user_info);
params.put("token", token);
params.put("domain", domain);
System.out.println(params.toString());
return UrlParse.createLinkString(params, true);
}
private static String createLinkString(Map<String, String> params, boolean encode) {
List<String> keys = new ArrayList<String>(params.keySet());
StringBuilder prestrSB = new StringBuilder();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (encode) {
try {
value = URLEncoder.encode(value, "GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
if (i == keys.size() - 1) {
prestrSB.append(key).append("=").append(value);
} else {
prestrSB.append(key).append("=").append(value).append("&");
}
}
return prestrSB.toString();
}
private String getUserInfo(String username){
JSONStringer user_info = new JSONStringer();
user_info.object();
user_info.key("username");
user_info.value(username);
user_info.endObject();
return user_info.toString();
}
private static String getMD5(String info) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(info.getBytes("UTF-8"));
byte[] md5Array = md5.digest();
return bytesToHex1(md5Array);
} catch (NoSuchAlgorithmException e) {
return "";
} catch (UnsupportedEncodingException e) {
return "";
}
}
private static String bytesToHex1(byte[] md5Array) {
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < md5Array.length; i++) {
int temp = 0xff & md5Array[i];
String hexString = Integer.toHexString(temp);
if (hexString.length() == 1) {
strBuilder.append("0").append(hexString);
} else {
strBuilder.append(hexString);
}
}
return strBuilder.toString();
}
}
2.3 单点登出接口
可选,仅用于私有化,在IDP退出时同时注销BDP的登录状态:
- 首先退出IDP登录状态
- 同时调用BDP的sls接口
- BDP注销登录状态
请求参数说明:
参数名称 | 参数类型 | 是否必填 | 默认值 | 参数描述 | 最大长度 |
---|---|---|---|---|---|
domain | string | 必填 | 无 | BDP企业域 | 无 |