创建一个简单的 MDM server(1)
前提:已获得 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 消息。你能够在数据库中查看到这两条消息。
创建一个简单的 MDM server(1)的更多相关文章
- 使用Python创建一个简易的Web Server
Python 2.x中自带了SimpleHTTPServer模块,到Python3.x中,该模块被合并到了http.server模块中.使用该模块,可以快速创建一个简易的Web服务器. 我们在C:\U ...
- spring cloud 创建一个简单Eureka Server
在Spring Cloud实现一个Eureka Server是一件非常简单的事情.下面我们来写一个Eureka Server DEMO. 编码 父项目pom.xml <?xml version= ...
- 《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型
第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以 ...
- 编写一个简单的Web Server
编写一个简单的Web Server其实是轻而易举的.如果我们只是想托管一些HTML页面,我们可以这么实现: 在VS2013中创建一个C# 控制台程序 编写一个字符串扩展方法类,主要用于在URL中截取文 ...
- [WCF学习笔记] 我的WCF之旅(1):创建一个简单的WCF程序
近日学习WCF,找了很多资料,终于找到了Artech这个不错的系列.希望能从中有所收获. 本文用于记录在学习和实践WCF过程中遇到的各种基础问题以及解决方法,以供日后回顾翻阅.可能这些问题都很基础,可 ...
- node创建一个简单的web服务
本文将如何用node创建一个简单的web服务,过程也很简单呢~ 开始之前要先安装node.js 1.创建一个最简单的服务 // server.js const http = require('http ...
- 用go和zk实现一个简单的分布式server
golang的zk客户端 最近打算写个简单的配置中心,考虑到实现便捷性,语言选择了go,由于其中计划用到zk,就调研了下golang的zk客户端,并实现了个简单的分布式server.最终找到了两个,地 ...
- 创建一个简单的 http 服务器
创建一个简单的 http 服务器 直接在 目录下运行 当前的目录即可是root 目录 默认端口8000 应该可以加参数修改端口号 Python2 python -m SimpleHTTPServer ...
- 如何创建一个简单 APT 仓库
0. 无废话版本 需求: 有一堆 .deb 包,想把它们做成一个 APT 仓库,这样就可以用apk install pkgname进行安装了,这样一方面自己可以规避 dpkg -i xxx.deb 时 ...
随机推荐
- 使用Promise
Promise所要解决的问题:回调地狱 asyncTask1(data, function (data1){ asyncTask2(data1, function (data2){ asyncTask ...
- 一个Linux下C线程池的实现
什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了.如果线程创建和销毁时间相比任 ...
- 关于JavaScript中Get/Set访问器
有时候大家可能会纳闷,在使用JavaScript的时候,只需要给一个系统变量赋值就可以触发一系列操作去相应. 但是我们在写Js的时候,修改了一个自定义变量,却连个P都没有.是不是很郁闷呢? 其实,我们 ...
- C# Timer使用方法示例
实例化一个timer: // 每5分钟执行一次,每次执行的间隔毫秒时长 System.Timers.Timer timer = new System.Timers.Timer(5*60*1000); ...
- 《practical Java》读书笔记
题记: 花了一周把Peter Haggar的<practical Java>看了遍,有所感悟,年纪大了, 写下笔记,方便日后查看.也希望有缘之人可以看看,做个渺小的指路人. 不足之处还望指 ...
- Retrofit2使用初探
首先需要导入这样两个包 compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4' compile 'com.squareup.retrofit2:co ...
- Es6 函数式编程 MayBe函子的简单示例
初级函子的作用非常简单,使用场景主要体现在:深入访问object的属性的时候,不会担心由于属性不存在.undefined.null等问题出现异常. MayBe.js var MayBe = funct ...
- 怎么样快速完整备份和压缩 很大的 sqlserver 1TB 数据库 -摘自网络
How to increase SQL Database Full Backup speed using compression and Solid State Disks The SQL 2008 ...
- js动态创建表格,删除行列的小例子
js动态创建表格,删除行列的实例代码. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &quo ...
- SVN的搭建与使用
1.什么是SVN? SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS.CVS,它采用了分支管理系统,它的设计目标就是取代CVS.互联网上很多版本控制服务已从CVS迁移到 ...