创建一个简单的 MDM server(1)

时间:2022-06-27 08:25:43

前提:已获得 APNS 证书 ,已完毕 MDM 配置描写叙述文件的制作。请參考《 MDM 证书申请流程 》一文和《配置MDM Provisioning Profile》。

环境:OSX 10.9.2,JDK 1.6。Eclipse JavaEE Helois,Tomcat 7.0

一、前言

《THE IOS MDMPROTOCOL》(即Inside Apple MDM)一文中描写叙述了一个简单 MDM Server Python 实现(server.py)。

笔者也曾參照此文配置,但在安装M2Crypto 一步时遇到一个 cc 參数没有定义错误。实在无法进行下去,因此不得不放弃。在參照《基于IOS上MDM技术相关资料整理及汇总》一文时,发现其使用了商业SSL证书(StartSSL)。而笔者使用的自签名SSL证书,有些步骤不太一样 ,另外在一些关键点也须要读者自己摸索,因此有了本文的诞生。

二、准备

无论 APNS 还是 MDM,都须要server实现 https。如果我们使用 Eclipse 调试 Tomcat,则须要改动 Servers 项目以下的Tomcat 配置文件 server.xml。详细过程请參考《开启 Tomcat https 服务》。

三、 实现 checkin URL

MDM 须要实现完整 APNS 服务,对此我们採用的是第三方的 java apns 实现。

主要是 notnoop 的 Java apns(不是google 的 JavaPNS),此外,还有 xmlwise ,用于解析苹果的 plist 文档。

java apns有两个包:apns-0.1.5.jar 和 apns-0.1.5-jar-with-dependencies.jar包。

前者是 API,后者是依赖包。

xmlwise 就一个包:xmlwise-1_2.jar。

数据库採用 mysql。因此也须要 mysql-connector-java-5.1.2-bin.jar包。

此外java apns 使用了slf4j。即 slf4j-simple-1.7.7.jar。

将 MDM push 证书 mdm_push.p12 和 provisioning 配置描写叙述文件 client.mobileconfig 放到WebContent 文件夹下。

用 MySQLWorkbench 连上 mysql 数据库,创建两张表。用于设备注冊:

CREATE TABLE `Authenticate` (

`UDID` varchar(40) NOT NULL,

`Topic` varchar(200) DEFAULTNULL,

`timestamp` timestamp NULLDEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY (`UDID`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `TokenUpdate` (

`UDID` varchar(40) NOT NULL,

`Topic` varchar(200) DEFAULTNULL,

`PushMagic` varchar(200)DEFAULT NULL,

`Token` varchar(200) DEFAULTNULL,

`UnlockToken` blob,

`timestamp` timestamp NULLDEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY (`UDID`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1;

首先看注冊服务。设备注冊由Servlet checkin 实现。其 doPut 方法例如以下:

System.out.println("*********ReceivedMessage:***********\n"+plistStr);

try{

Map<String,Object>plist=Plist.fromXml(plistStr);

if(plist!=null){

StringMessageType=plist.get("MessageType").toString();

if(MessageType.equals("Authenticate")){

Authenticate au=newAuthenticate(plist.get("UDID").toString(),plist.get("Topic").toString());

au.save();

}elseif(MessageType.equals("TokenUpdate")){

Stringregex="Token</key>\\s*<data>\\s*([^\\s]*)\\s*</data>";

String tokenStr=Utils.regxCatch(plistStr,regex);

System.out.println("catches tokens:"+tokenStr);

TokenUpdate tu=new TokenUpdate(plist);

tu.Token=tokenStr;

tu.save();

}

response.getWriter().println(Utils.emptyPlist());

}

}catch(Exceptione){

e.printStackTrace();

}

checkin 主要处理与注冊相关的两种消息:Authenticate 和 TokenUpdate。

在设备注冊中,server首先收到Authenticate 消息,checkin 将之计入 Authenticate 表,然后返回一个空的 plist 文件。设备随后会发来TokenUpdate 消息。checkin 也会将之存到 TokenUpdate 表并返回空 plist 文件。在 TokenUpdate 消息的处理中,checkin获取的是 UDID、device token、push magic和 unlock 等 MDM push中将要用到的重要字段。

当中,token(即 APNS 中的 device token)须要特别注意。

由于在苹果的文档中说,这是一个32位长度的字符串。

实际上我们都知道APNS 中,device token 是一个 byte 数组。

在 TokenUpdate 消息中,iOS 将 device token 的 byte 数组进行了base64 编码,结果变成了一个 44 字节长度的 string。也就是说在 TokenUpdate 消息中。<token>字段的值类型应该是<string>,而不应该是消息中定义的<data>。

一个典型的 TokenUpdate 消息,其 token 描写叙述例如以下:

<key>Token</key>

<data> [ 32 byte string, base64 encoded,redacted ]</data>

显然,这里的<data>必须换成<string>。xmlwise 包中的 Plist 类才干正确解析。

由于在 Plist 类中,对于 plist 文件里的数据类型<data>会被解析为 byte 数组而不是字符串。

因此 checkin 在处理 TokenUpdate 消息时。採取了额外的手段来获取 token 字段,即正则捕获。

执行 Tomcat server,将 iPad 接入server统一 wifi 网络,然后在浏览器中訪问描写叙述文件地址:

https://192.168.2.1:8443/mdmtest/client.mobileconfig

此时 safari 将调用设置程序,在客户端安装 mdm 配置描写叙述文件。当你点击“安装”button,iPad 会请求 checkin URL地址,并发送Authenticate 消息和 TokenUpdate 消息。你能够在数据库中查看到这两条消息。