apple_class_client 0.0.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/README.md +4 -0
- data/apple_class_client.gemspec +4 -2
- data/lib/apple_class_client.rb +6 -1
- data/lib/apple_class_client/auth.rb +51 -0
- data/lib/apple_class_client/configuration.rb +44 -0
- data/lib/apple_class_client/error.rb +47 -0
- data/lib/apple_class_client/hacks/typhoeus_request.rb +57 -0
- data/lib/apple_class_client/request.rb +41 -0
- data/lib/apple_class_client/version.rb +1 -1
- metadata +46 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cf5ca3c450a74dc4dbf1f8cd9b09b6ce72ca48e8
|
|
4
|
+
data.tar.gz: 1f416edf07f9f13a9142616b22b85c3580427e38
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e12f5ff91b5812b61bc4e234f8dab2a377fa26b7cb5492c5dd5c607a0e4aae0e6e72fa5f21ee67b7717fa291e48cdf0efc182dc9e9a6cbc0572e20220dd122f3
|
|
7
|
+
data.tar.gz: 1c4a46b7b2f31a6f483941b8a9447031244eca2414d157ad27a02f91a38aa47ffe71f6cb6400ba81999d433dbe71c02574a154a67f67a05d730da0c19252ea09
|
data/CHANGELOG.md
CHANGED
data/CODE_OF_CONDUCT.md
CHANGED
|
@@ -35,7 +35,7 @@ This code of conduct applies both within project spaces and in public spaces
|
|
|
35
35
|
when an individual is representing the project or its community.
|
|
36
36
|
|
|
37
37
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
38
|
-
reported by contacting a project maintainer at
|
|
38
|
+
reported by contacting a project maintainer at aywang31@gmail.com. All
|
|
39
39
|
complaints will be reviewed and investigated and will result in a response that
|
|
40
40
|
is deemed necessary and appropriate to the circumstances. Maintainers are
|
|
41
41
|
obligated to maintain confidentiality with regard to the reporter of an
|
data/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# AppleClassClient
|
|
2
2
|
|
|
3
|
+
[ ](https://app.codeship.com/projects/152119)
|
|
4
|
+
[](https://codeclimate.com/github/albertyw/apple_class_client)
|
|
5
|
+
[](https://gemnasium.com/github.com/albertyw/apple_class_client)
|
|
6
|
+
|
|
3
7
|
This is a client for accessing Apple MDM's class, person, location, and course rosters.
|
|
4
8
|
|
|
5
9
|
## Installation
|
data/apple_class_client.gemspec
CHANGED
|
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
|
7
7
|
spec.name = "apple_class_client"
|
|
8
8
|
spec.version = AppleClassClient::VERSION
|
|
9
9
|
spec.authors = ["Albert Wang"]
|
|
10
|
-
spec.email = ["
|
|
10
|
+
spec.email = ["aywang31@gmail.com"]
|
|
11
11
|
|
|
12
12
|
spec.summary = %q{Client for accessing Apple MDM class information}
|
|
13
13
|
spec.description = %q{This is a client for accessing Apple MDM's class, person, location, and course rosters.}
|
|
@@ -19,7 +19,9 @@ Gem::Specification.new do |spec|
|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
20
20
|
spec.require_paths = ["lib"]
|
|
21
21
|
|
|
22
|
+
spec.add_dependency "oauth", "~> 0.4"
|
|
23
|
+
spec.add_dependency "typhoeus", [">= 0.7", "< 1.2"]
|
|
22
24
|
spec.add_development_dependency "bundler", "~> 1.12"
|
|
23
|
-
spec.add_development_dependency "rake", "
|
|
25
|
+
spec.add_development_dependency "rake", ">= 11.0"
|
|
24
26
|
spec.add_development_dependency "rspec", "~> 3.0"
|
|
25
27
|
end
|
data/lib/apple_class_client.rb
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
require "apple_class_client/version"
|
|
2
|
+
require "apple_class_client/configuration"
|
|
2
3
|
|
|
3
4
|
module AppleClassClient
|
|
4
|
-
|
|
5
|
+
extend Configuration
|
|
5
6
|
end
|
|
7
|
+
|
|
8
|
+
require "apple_class_client/auth"
|
|
9
|
+
require "apple_class_client/error"
|
|
10
|
+
require "apple_class_client/request"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Apple Session Authorization Token management
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "oauth"
|
|
5
|
+
require File.join(File.dirname(__FILE__), "hacks", "typhoeus_request")
|
|
6
|
+
require "securerandom"
|
|
7
|
+
require "typhoeus"
|
|
8
|
+
|
|
9
|
+
module AppleClassClient
|
|
10
|
+
module Auth
|
|
11
|
+
# Apple requires a quirky OAuth 1.0a authentication to get a temporary
|
|
12
|
+
# X-ADM-Auth-Session key to make requests; this takes care of that
|
|
13
|
+
|
|
14
|
+
OAUTH_PATH = "/session"
|
|
15
|
+
|
|
16
|
+
def self.get_session_token
|
|
17
|
+
options = { method: :get, headers: AppleClassClient::Request::DEFAULT_HEADERS }
|
|
18
|
+
request = Typhoeus::Request.new(AppleClassClient::Request.make_url(OAUTH_PATH), options)
|
|
19
|
+
request.options[:headers].merge!({ "Authorization" => oauth_header(request) })
|
|
20
|
+
request.run
|
|
21
|
+
response = request.response
|
|
22
|
+
AppleClassClient::Error.check_request_error(response, auth: true)
|
|
23
|
+
parse_response response
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.oauth_header(request)
|
|
27
|
+
consumer = OAuth::Consumer.new(
|
|
28
|
+
AppleClassClient.consumer_key,
|
|
29
|
+
AppleClassClient.consumer_secret,
|
|
30
|
+
site: AppleClassClient::Request.make_url(OAUTH_PATH),
|
|
31
|
+
)
|
|
32
|
+
token = OAuth::AccessToken.new(
|
|
33
|
+
consumer,
|
|
34
|
+
AppleClassClient.access_token,
|
|
35
|
+
AppleClassClient.access_secret,
|
|
36
|
+
)
|
|
37
|
+
oauth_params = {
|
|
38
|
+
consumer: consumer,
|
|
39
|
+
realm: "ADM",
|
|
40
|
+
token: token,
|
|
41
|
+
}
|
|
42
|
+
oauth_helper = OAuth::Client::Helper.new request, oauth_params.merge(request_uri: AppleClassClient::Request.make_url(OAUTH_PATH))
|
|
43
|
+
oauth_helper.header
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.parse_response(response)
|
|
47
|
+
body = JSON.parse response.response_body
|
|
48
|
+
auth_session_token = body["auth_session_token"]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Configuration for AppleClassClient
|
|
2
|
+
# Configuration values can be either literals or Procs; note that Procs will not
|
|
3
|
+
# be overwritten by AppleClassClient::Token.save_data
|
|
4
|
+
|
|
5
|
+
module AppleClassClient
|
|
6
|
+
module Configuration
|
|
7
|
+
CONFIG = {
|
|
8
|
+
private_key: nil, # MDM Server's private key for decrypting token files
|
|
9
|
+
consumer_key: nil, # Server Token information
|
|
10
|
+
consumer_secret: nil,
|
|
11
|
+
access_token: nil,
|
|
12
|
+
access_secret: nil,
|
|
13
|
+
access_token_expiry: nil,
|
|
14
|
+
apple_mdm_server: "https://mdmenrollment.apple.com", # Apple MDM server url
|
|
15
|
+
user_agent: "CellabusMDM",
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
CONFIG.freeze
|
|
19
|
+
|
|
20
|
+
attr_writer *CONFIG.keys
|
|
21
|
+
|
|
22
|
+
def method_missing(m, *_args, &_block)
|
|
23
|
+
if CONFIG.keys.include? m.to_sym
|
|
24
|
+
get_value(m)
|
|
25
|
+
else
|
|
26
|
+
raise NoMethodError, "Unknown method #{m}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def get_value(m)
|
|
31
|
+
value = instance_variable_get("@#{m}")
|
|
32
|
+
value = get_default_value(m) if value.nil?
|
|
33
|
+
(value.is_a? Proc) ? value.call : value
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def get_default_value(key)
|
|
37
|
+
CONFIG[key.to_sym]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def configure
|
|
41
|
+
yield self
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Errors for AppleClassClient and Apple's endpoints
|
|
2
|
+
|
|
3
|
+
require 'typhoeus'
|
|
4
|
+
|
|
5
|
+
module AppleClassClient
|
|
6
|
+
module Error
|
|
7
|
+
AUTH_ERRORS = [
|
|
8
|
+
# Used by AppleClassClient::Auth
|
|
9
|
+
["BadRequest", 400, ""],
|
|
10
|
+
["Unauthorized", 401, ""],
|
|
11
|
+
["Forbidden", 403, ""],
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
ERRORS = [
|
|
15
|
+
# Server failures
|
|
16
|
+
["InternalServerError", 500, ""],
|
|
17
|
+
["ServiceUnavailable", 503, ""],
|
|
18
|
+
|
|
19
|
+
# Client errors
|
|
20
|
+
["Unauthorized", 401, "UNAUTHORIZED"],
|
|
21
|
+
["Forbidden", 403, "FORBIDDEN"],
|
|
22
|
+
["MalformedRequest", 400, "MALFORMED_REQUEST_BODY"],
|
|
23
|
+
["CursorRequired", 400, "CURSOR_REQUIRED"],
|
|
24
|
+
["InvalidCursor", 400, "INVALID_CURSOR"],
|
|
25
|
+
["ExpiredCursor", 400, "EXPIRED_CURSOR"],
|
|
26
|
+
["TooManyRequests", 429, "TOO_MANY_REQUESTS"],
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
def self.check_request_error(response, auth:false)
|
|
30
|
+
get_errors(auth: auth).each do |error_name, response_code, body|
|
|
31
|
+
if response.code == response_code && response.body.include?(body)
|
|
32
|
+
raise RequestError, error_name
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
if response.code != 200
|
|
36
|
+
raise RequestError, "GenericError"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.get_errors(auth:false)
|
|
41
|
+
auth ? AUTH_ERRORS : ERRORS
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class RequestError < RuntimeError
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# This contains a few hacks that adds support for non-ancient versions of Typhoeus to
|
|
2
|
+
# the ancient dead ruby oauth gem
|
|
3
|
+
|
|
4
|
+
require "oauth/request_proxy/base"
|
|
5
|
+
require "typhoeus"
|
|
6
|
+
require "typhoeus/request"
|
|
7
|
+
require "uri"
|
|
8
|
+
require "cgi"
|
|
9
|
+
|
|
10
|
+
module OAuth::RequestProxy::Typhoeus
|
|
11
|
+
class Request < OAuth::RequestProxy::Base
|
|
12
|
+
# Proxy for signing Typhoeus::Request requests
|
|
13
|
+
# Usage example:
|
|
14
|
+
# oauth_params = {:consumer => oauth_consumer, :token => access_token}
|
|
15
|
+
# req = Typhoeus::Request.new(uri, options)
|
|
16
|
+
# oauth_helper = OAuth::Client::Helper.new(req, oauth_params.merge(:request_uri => uri))
|
|
17
|
+
# req.headers.merge!({"Authorization" => oauth_helper.header})
|
|
18
|
+
# hydra = Typhoeus::Hydra.new()
|
|
19
|
+
# hydra.queue(req)
|
|
20
|
+
# hydra.run
|
|
21
|
+
# response = req.response
|
|
22
|
+
proxies Typhoeus::Request
|
|
23
|
+
|
|
24
|
+
def method
|
|
25
|
+
request_method = request.options[:method].to_s.upcase
|
|
26
|
+
request_method.empty? ? "GET" : request_method
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def uri
|
|
30
|
+
options[:uri].to_s
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def parameters
|
|
34
|
+
if options[:clobber_request]
|
|
35
|
+
options[:parameters]
|
|
36
|
+
else
|
|
37
|
+
post_parameters.merge(query_parameters).merge(options[:parameters] || {})
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def query_parameters
|
|
44
|
+
query = URI.parse(request.url).query
|
|
45
|
+
query ? CGI.parse(query) : {}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def post_parameters
|
|
49
|
+
# Post params are only used if posting form data
|
|
50
|
+
if method == "POST"
|
|
51
|
+
OAuth::Helper.stringify_keys(request.params || {})
|
|
52
|
+
else
|
|
53
|
+
{}
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Wrapper around requests to MDM class endpoint
|
|
2
|
+
# Will also handle any error conditions
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require "typhoeus"
|
|
6
|
+
|
|
7
|
+
module AppleClassClient
|
|
8
|
+
module Request
|
|
9
|
+
DEFAULT_HEADERS = {
|
|
10
|
+
"User-Agent" => "#{AppleClassClient.user_agent}/#{AppleClassClient::VERSION}",
|
|
11
|
+
"X-Server-Protocol-Version" => "2",
|
|
12
|
+
"Content-Type" => "application/json;charset=UTF8",
|
|
13
|
+
}
|
|
14
|
+
DEFAULT_HEADERS.freeze
|
|
15
|
+
|
|
16
|
+
def self.make_request(url, query_type, body, params:nil, headers:nil)
|
|
17
|
+
if headers == nil
|
|
18
|
+
headers = make_headers
|
|
19
|
+
end
|
|
20
|
+
request = Typhoeus::Request.new(
|
|
21
|
+
url,
|
|
22
|
+
method: query_type,
|
|
23
|
+
body: body,
|
|
24
|
+
params: params,
|
|
25
|
+
headers: headers,
|
|
26
|
+
)
|
|
27
|
+
request.run
|
|
28
|
+
AppleClassClient::Error.check_request_error request.response
|
|
29
|
+
JSON.parse request.response.body
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.make_headers
|
|
33
|
+
session_auth_token = AppleClassClient::Auth.get_session_token
|
|
34
|
+
DEFAULT_HEADERS.merge("X-ADM-Auth-Session" => session_auth_token)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.make_url(path)
|
|
38
|
+
AppleClassClient.apple_mdm_server + path
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
metadata
CHANGED
|
@@ -1,15 +1,49 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: apple_class_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Albert Wang
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2017-05-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: oauth
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.4'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.4'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: typhoeus
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0.7'
|
|
34
|
+
- - "<"
|
|
35
|
+
- !ruby/object:Gem::Version
|
|
36
|
+
version: '1.2'
|
|
37
|
+
type: :runtime
|
|
38
|
+
prerelease: false
|
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0.7'
|
|
44
|
+
- - "<"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.2'
|
|
13
47
|
- !ruby/object:Gem::Dependency
|
|
14
48
|
name: bundler
|
|
15
49
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -28,16 +62,16 @@ dependencies:
|
|
|
28
62
|
name: rake
|
|
29
63
|
requirement: !ruby/object:Gem::Requirement
|
|
30
64
|
requirements:
|
|
31
|
-
- - "
|
|
65
|
+
- - ">="
|
|
32
66
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
67
|
+
version: '11.0'
|
|
34
68
|
type: :development
|
|
35
69
|
prerelease: false
|
|
36
70
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
71
|
requirements:
|
|
38
|
-
- - "
|
|
72
|
+
- - ">="
|
|
39
73
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
74
|
+
version: '11.0'
|
|
41
75
|
- !ruby/object:Gem::Dependency
|
|
42
76
|
name: rspec
|
|
43
77
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -55,7 +89,7 @@ dependencies:
|
|
|
55
89
|
description: This is a client for accessing Apple MDM's class, person, location, and
|
|
56
90
|
course rosters.
|
|
57
91
|
email:
|
|
58
|
-
-
|
|
92
|
+
- aywang31@gmail.com
|
|
59
93
|
executables: []
|
|
60
94
|
extensions: []
|
|
61
95
|
extra_rdoc_files: []
|
|
@@ -71,6 +105,11 @@ files:
|
|
|
71
105
|
- bin/console
|
|
72
106
|
- bin/setup
|
|
73
107
|
- lib/apple_class_client.rb
|
|
108
|
+
- lib/apple_class_client/auth.rb
|
|
109
|
+
- lib/apple_class_client/configuration.rb
|
|
110
|
+
- lib/apple_class_client/error.rb
|
|
111
|
+
- lib/apple_class_client/hacks/typhoeus_request.rb
|
|
112
|
+
- lib/apple_class_client/request.rb
|
|
74
113
|
- lib/apple_class_client/version.rb
|
|
75
114
|
homepage: https://github.com/albertyw/apple_class_client
|
|
76
115
|
licenses:
|