iOS MDM - отправка push-уведомлений MDM из Java?
Я работаю над простым сервером управления мобильными устройствами iOS (MDM) на Java в качестве ментального упражнения и подтверждения концепции. До сих пор у меня есть ряд конечных точек службы JAX-RS RESTful, которые позволяют мне:
- Начальная регистрация устройства
- Начальная регистрация сертификата MDM (SCEP)
- Регистрация сертификата устройства (SCEP)
- Установка полезной нагрузки профиля МДМ
Мой профиль MDM выглядит примерно так. Он настраивает сертификат устройства с помощью SCEP и устанавливает информацию об URL-адресе регистрации и самом MDM:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Inc//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>6470eee3-88e1-44fd-b301-7e51872822dd</string>
<key>PayloadIdentifier</key>
<string>org.example.mymdm.checkin</string>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadContent</key>
<dict>
<key>URL</key>
<string>https://mymdmserver:8443/mdm/scep</string>
<key>Name</key>
<string>EnrollmentCAInstance</string>
<key>Subject</key>
<array>
<array>
<array>
<string>O</string>
<string>Example, Inc.</string>
</array>
</array>
<array>
<array>
<string>CN</string>
<string>User Device Cert2</string>
</array>
</array>
</array>
<key>Challenge</key>
<string>MyChallengeGoesHere</string>
<key>Keysize</key>
<integer>2048</integer>
<key>Key Type</key>
<string>RSA</string>
<key>Key Usage</key>
<integer>5</integer>
</dict>
<key>PayloadDescription</key>
<string>Provides device encryption identity</string>
<key>PayloadUUID</key>
<string>be730dbc-3d6e-462c-8368-34cec86e2acd</string>
<key>PayloadType</key>
<string>com.apple.security.scep</string>
<key>PayloadDisplayName</key>
<string>Encryption Identity</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadOrganization</key>
<string>Example, Inc.</string>
<key>PayloadIdentifier</key>
<string>com.example.profileservice.scep.be730dbc-3d6e-462c-8368-34cec86e2acd</string>
</dict>
<dict>
<key>AccessRights</key>
<integer>8191</integer>
<key>CheckInURL</key>
<string>https://mymdmserver:8443/mdm/checkin</string>
<key>CheckOutWhenRemoved</key>
<true/>
<key>IdentityCertificateUUID</key>
<string>be730dbc-3d6e-462c-8368-34cec86e2acd</string>
<key>PayloadDescription</key>
<string>Checkin</string>
<key>PayloadDisplayName</key>
<string>Checkin</string>
<key>PayloadIdentifier</key>
<string>com.apple.mdm.995191e6-b387-47c6-98d1-c00a25d95047</string>
<key>PayloadOrganization</key>
<string>Gener-Tech</string>
<key>PayloadType</key>
<string>com.apple.mdm</string>
<key>PayloadUUID</key>
<string>527228e9-8094-40b8-89ce-7c5b09ad348b</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>ServerURL</key>
<string>https://mymdmserver:8443/mdm/checkin</string>
<key>SignMessage</key>
<true/>
<key>Topic</key>
<string>com.apple.mgmt.External.*</string>
<key>UseDevelopmentAPNS</key>
<false/>
</dict>
</array>
</dict>
</plist>
После завершения беспроводной установки я вижу конфигурацию и сертификат устройства на моем устройстве iOS. Я также вижу вызов моей конечной точки /checkin, содержащей значения PushMagic и токена устройства для APNS. Именно в этот момент я сталкиваюсь с контрольно-пропускным пунктом.
Я использую библиотеку java-apns, чтобы попытаться отправить push-уведомление через APNS на мое устройство с помощью PushMagic и токена устройства. Мой звонок выглядит примерно так:
ApnsService apns = APNS.newService().withCert(Thread.currentThread().getContextClassLoader().getResourceAsStream("MDM_APNS_Cert.p12"),
certPassword)
.withAppleDestination(true).build();
byte[] tokenBytes = Base64.decodeBase64(deviceToken.getBytes());
String hexToken = Hex.encodeHexString(tokenBytes);
String pushNotificationPayload = APNS.newPayload().mdm(pushMagic).build();
ApnsNotification response = apns.push(hexToken, pushNotificationPayload);
Однако, когда я пытаюсь отправить push-уведомление, я вижу ошибки в моих журналах, которые выглядят примерно так:
13:29:55,133 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-2) Error-response packet 080800000002
13:29:55,133 DEBUG [com.notnoop.apns.internal.Utilities] (MonitoringThread-2) close 6a86b59d[SSL_RSA_WITH_3DES_EDE_CBC_SHA: Socket[addr=gateway.push.apple.com/17.188.147.157,port=2195,localport=58884]]
13:29:55,133 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-2) Closed connection cause=INVALID_TOKEN; id=2
13:29:55,133 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-2) Candidate for removal, message id 2
13:29:55,133 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-2) Bad message found 2
13:29:55,133 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-2) delegate.messageSendFailed, message id 2
13:29:55,133 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-2) resending 0 notifications
13:29:55,133 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-2) Monitoring input stream closed by EOF
13:29:55,133 DEBUG [com.notnoop.apns.internal.Utilities] (MonitoringThread-2) close 6a86b59d[SSL_RSA_WITH_3DES_EDE_CBC_SHA: Socket[addr=gateway.push.apple.com/17.188.147.157,port=2195,localport=58884]]
13:29:55,133 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-2) draining buffer
Есть идеи, что здесь может происходить? Насколько я понимаю, push-уведомление должно быть получено устройством iOS, а затем оно будет называть URL-адрес, определенный в профиле MDM, как ServerURL. Это не правильно? Я неправильно понимаю поток здесь? Как я могу исправить проблему с помощью моего push-уведомления MDM?
ОБНОВЛЕНИЕ: Итак, я попробовал протестировать 2 способа: использование библиотеки java-apns и использование curl. С curl моя команда выглядит так:
curl -vk -E ./MDMPushCert.pem -d '{"aps":{"mdm":"<PUSH MAGIC VALUE FROM CHECKIN>"}}' -H "apns-topic: com.apple.mgmt.XServer.<UUID FROM PUSH CERT>" -H "apns-priority: 10" https://api.push.apple.com/3/device/<DEVICE TOKEN FROM CHECKIN>
Команда curl завершается неудачно, однако с ошибкой {"reason":"BadDeviceToken"}
несмотря на то, что я копирую и вставляю значение, предоставленное устройством при вызове /checkin
конечная точка. Полный вывод выглядит так:
* Trying 17.188.152.35...
* TCP_NODELAY set
* Connected to api.push.apple.com (17.188.152.35) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=api.push.apple.com; OU=management:idms.group.533599; O=Apple Inc.; ST=California; C=US
* start date: Sep 5 17:11:04 2017 GMT
* expire date: Oct 5 17:11:04 2019 GMT
* issuer: CN=Apple IST CA 2 - G1; OU=Certification Authority; O=Apple Inc.; C=US
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7fdbf7809400)
> POST /3/device/<TOKEN FROM CHECKIN>
0 HTTP/2
> Host: api.push.apple.com
> User-Agent: curl/7.54.0
> Accept: */*
> apns-topic: com.apple.mgmt.XServer.<UUID FROM APNS CERT>
> apns-priority: 10
> Content-Length: 54
> Content-Type: application/x-www-form-urlencoded
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
* We are completely uploaded and fine
< HTTP/2 400
< apns-id: 7E178A20-9C17-8E21-592F-185E02D17F14
<
* Connection #0 to host api.push.apple.com left intact
{"reason":"BadDeviceToken"}
Сам push-сертификат был сгенерирован путем установки macOS Server на macOS High Sierra и последующего экспорта сертификата, сгенерированного при установке Profile Server. Чего я не понимаю, так это того, почему я получаю неверную ошибку токена, когда токен пришел непосредственно с самого устройства. Я предполагаю, что это та же самая ошибка, вызывающая сбой моего вызова java-apns. Результат этого вызова выглядит следующим образом:
09:04:10,735 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (default task-75) sendMessage Message(Id=1; Token=7BC93DC7AF930EED7379899B4E3FB9676DDABDCBA7B4F39D5E7654ECDC3F1DD0; Payload={"mdm":"4A846CEF-3241-426E-B451-F258E4B1ABA6"}) fromBuffer: false
09:04:10,803 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (default task-75) Connected new socket 3e1dae5f[SSL_NULL_WITH_NULL_NULL: Socket[addr=gateway.push.apple.com/17.188.168.12,port=2195,localport=64265]]
09:04:10,803 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (default task-75) Launching Monitoring Thread for socket 3e1dae5f[SSL_NULL_WITH_NULL_NULL: Socket[addr=gateway.push.apple.com/17.188.168.12,port=2195,localport=64265]]
09:04:10,805 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (default task-75) Made a new connection to APNS
09:04:10,805 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-1) Started monitoring thread
09:04:10,920 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (default task-75) draining buffer
09:04:10,921 DEBUG [com.mymdm.rest.test.TestMDMService] (default task-75) push(HttpServletRequest, HttpServletResponse) - ApnsNotification response=Message(Id=1; Token=7BC93DC7AF930EED7379899B4E3FB9676DDABDCBA7B4F39D5E7654ECDC3F1DD0; Payload={"mdm":"4A846CEF-3241-426E-B451-F258E4B1ABA6"})
09:04:10,921 DEBUG [com.mymdm.rest.test.TestMDMService] (default task-75) push(HttpServletRequest, HttpServletResponse) - end
09:04:10,962 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-1) Error-response packet 080800000001
09:04:10,962 DEBUG [com.notnoop.apns.internal.Utilities] (MonitoringThread-1) close 3e1dae5f[SSL_RSA_WITH_3DES_EDE_CBC_SHA: Socket[addr=gateway.push.apple.com/17.188.168.12,port=2195,localport=64265]]
09:04:10,964 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-1) Closed connection cause=INVALID_TOKEN; id=1
09:04:10,964 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-1) Candidate for removal, message id 1
09:04:10,964 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-1) Bad message found 1
09:04:10,964 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-1) delegate.messageSendFailed, message id 1
09:04:10,964 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-1) resending 0 notifications
09:04:10,964 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-1) Monitoring input stream closed by EOF
09:04:10,965 DEBUG [com.notnoop.apns.internal.Utilities] (MonitoringThread-1) close 3e1dae5f[SSL_RSA_WITH_3DES_EDE_CBC_SHA: Socket[addr=gateway.push.apple.com/17.188.168.12,port=2195,localport=64265]]
09:04:10,965 DEBUG [com.notnoop.apns.internal.ApnsConnectionImpl] (MonitoringThread-1) draining buffer