cztop 0.8.0 → 0.9.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/CHANGES.md +6 -0
- data/README.md +1 -0
- data/lib/cztop/authenticator.rb +16 -6
- data/lib/cztop/cert_store.rb +42 -0
- data/lib/cztop/version.rb +1 -1
- data/lib/cztop/zap.rb +234 -0
- data/lib/cztop/zsock_options.rb +1 -1
- data/lib/cztop.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8c82a0f35f091e2d464beabb00adaf5ad0f0b35
|
4
|
+
data.tar.gz: aa92e0a78ca5ca7dcc00441d16e004085024a60a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 792e7990a6451bd7f02b638e02c782c95c9d54cbc009aa371de33234ed84b06d88737f830406363e96b44425f643c051948a57aa81719e9059627c48252a308b
|
7
|
+
data.tar.gz: 1af4724a36e2959e1e94f552c9289e51f98aa5565df5bb6c14cc8a99130401fd4713fa3f75090e2dcdc9cc466521d7e2a51bea756df20d34a10767767d3822d8
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
0.9.0 (10/20/2016)
|
2
|
+
-----
|
3
|
+
* add CertStore interface to zcertstore
|
4
|
+
* add ability to pass an existing CertStore to Authenticator
|
5
|
+
* add ZAP Request/Response classes (useful for testing)
|
6
|
+
|
1
7
|
0.8.0 (09/25/2016)
|
2
8
|
-----
|
3
9
|
* update dependency of czmq-ffi-gen to "~> 0.10.0"
|
data/README.md
CHANGED
@@ -97,6 +97,7 @@ Here's an overview of the core classes:
|
|
97
97
|
* [Z85](http://www.rubydoc.info/gems/cztop/CZTop/Z85)
|
98
98
|
* [Padded](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Padded) < Z85
|
99
99
|
* [Pipe](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Pipe)
|
100
|
+
* [ZAP](http://www.rubydoc.info/gems/cztop/CZTop/ZAP)
|
100
101
|
|
101
102
|
More information in the [API documentation](http://www.rubydoc.info/github/paddor/cztop).
|
102
103
|
|
data/lib/cztop/authenticator.rb
CHANGED
@@ -18,8 +18,18 @@ module CZTop
|
|
18
18
|
# This installs authentication on all {Socket}s and {Actor}s. Until you
|
19
19
|
# add policies, all incoming _NULL_ connections are allowed,
|
20
20
|
# and all _PLAIN_ and _CURVE_ connections are denied.
|
21
|
-
|
22
|
-
|
21
|
+
#
|
22
|
+
# @param cert_store [CertStore] a custom certificate store
|
23
|
+
# @note If you pass a {CertStore}, its native object will be owned by the
|
24
|
+
# actor (and freed by it when the actor terminates). That means you MUST
|
25
|
+
# disale auto free in the CertStore object.
|
26
|
+
def initialize(cert_store = nil)
|
27
|
+
if cert_store
|
28
|
+
raise ArgumentError unless cert_store.is_a?(CertStore)
|
29
|
+
cert_store = cert_store.ffi_delegate
|
30
|
+
cert_store.__undef_finalizer # native object is now owned by zauth() actor
|
31
|
+
end
|
32
|
+
@actor = Actor.new(ZAUTH_FPTR, cert_store)
|
23
33
|
end
|
24
34
|
|
25
35
|
# @return [Actor] the actor behind this authenticator
|
@@ -72,17 +82,17 @@ module CZTop
|
|
72
82
|
@actor.wait
|
73
83
|
end
|
74
84
|
|
75
|
-
|
85
|
+
# used to allow any CURVE client
|
86
|
+
ALLOW_ANY = "*"
|
76
87
|
|
77
88
|
# Configure CURVE authentication, using a directory that holds all public
|
78
89
|
# client certificates, i.e. their public keys. The certificates must have been
|
79
90
|
# created using {Certificate#save}/{Certificate#save_public}. You can add
|
80
91
|
# and remove certificates in that directory at any time.
|
81
92
|
#
|
82
|
-
# @param directory [String] the directory to take the keys from
|
83
|
-
# default value will allow any certificate)
|
93
|
+
# @param directory [String] the directory to take the keys from
|
84
94
|
# @return [void]
|
85
|
-
def curve(directory =
|
95
|
+
def curve(directory = ALLOW_ANY)
|
86
96
|
@actor << ["CURVE", directory]
|
87
97
|
@actor.wait
|
88
98
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module CZTop
|
2
|
+
|
3
|
+
# A store for CURVE security certificates, either backed by files on disk or
|
4
|
+
# in-memory.
|
5
|
+
#
|
6
|
+
# @see http://api.zeromq.org/czmq3-0:zcertstore
|
7
|
+
class CertStore
|
8
|
+
include ::CZMQ::FFI
|
9
|
+
include HasFFIDelegate
|
10
|
+
extend CZTop::HasFFIDelegate::ClassMethods
|
11
|
+
|
12
|
+
# Initializes a new certificate store.
|
13
|
+
#
|
14
|
+
# @param location [String, #to_s, nil] location the path to the
|
15
|
+
# directories to load certificates from, or nil if no certificates need
|
16
|
+
# to be loaded from the disk
|
17
|
+
def initialize(location = nil)
|
18
|
+
location = location.to_s if location
|
19
|
+
attach_ffi_delegate(Zcertstore.new(location))
|
20
|
+
end
|
21
|
+
|
22
|
+
# Looks up a certificate in the store by its public key.
|
23
|
+
#
|
24
|
+
# @param pubkey [String] the public key in question, in Z85 format
|
25
|
+
# @return [Certificate] the matching certificate, if found
|
26
|
+
# @return [nil] if no matching certificate was found
|
27
|
+
def lookup(pubkey)
|
28
|
+
ptr = ffi_delegate.lookup(pubkey)
|
29
|
+
return nil if ptr.null?
|
30
|
+
Certificate.from_ffi_delegate(ptr)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Inserts a new certificate into the store.
|
34
|
+
#
|
35
|
+
# @param cert [Certificate] the certificate to insert
|
36
|
+
# @return [void]
|
37
|
+
def insert(cert)
|
38
|
+
raise ArgumentError unless cert.is_a?(Certificate)
|
39
|
+
ffi_delegate.insert(cert.ffi_delegate)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/cztop/version.rb
CHANGED
data/lib/cztop/zap.rb
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
module CZTop
|
2
|
+
# This module provides two classes useful when implementing your own ZAP
|
3
|
+
# authentication handler or when directly communicating with one. Within
|
4
|
+
# CZTop, it's merely used for testing.
|
5
|
+
#
|
6
|
+
# Some of the features:
|
7
|
+
# * useful for both sides of the ZAP communication, i.e. useful for testing
|
8
|
+
# * security mechanism agnostic
|
9
|
+
# * protocol errors, version mismatches, and internal errors as exceptions
|
10
|
+
# * useful to implement your own ZAP handler
|
11
|
+
#
|
12
|
+
# @note This is not needed to be able to use {CZTop::Authenticator}!
|
13
|
+
# @see https://rfc.zeromq.org/spec:27/ZAP
|
14
|
+
module ZAP
|
15
|
+
# the endpoint a ZAP authenticator has bound to
|
16
|
+
ENDPOINT = "inproc://zeromq.zap.01"
|
17
|
+
|
18
|
+
# the ZAP version supported by this code
|
19
|
+
VERSION = "1.0"
|
20
|
+
|
21
|
+
# superclass for ZAP errors
|
22
|
+
class Error < StandardError
|
23
|
+
end
|
24
|
+
|
25
|
+
# used when the response contains an unsupported version
|
26
|
+
class VersionMismatch < Error
|
27
|
+
end
|
28
|
+
|
29
|
+
# security mechanisms mentioned in ZeroMQ RFC 27.
|
30
|
+
module Mechanisms
|
31
|
+
NULL = "NULL"
|
32
|
+
PLAIN = "PLAIN"
|
33
|
+
CURVE = "CURVE"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Represents a ZAP request.
|
37
|
+
class Request
|
38
|
+
# Crafts a new {Request} from a message.
|
39
|
+
#
|
40
|
+
# @param msg [CZTop::message] the message
|
41
|
+
# @return [Request] the request
|
42
|
+
# @raise [VersionMismatch] if the message contains an unsupported version
|
43
|
+
def self.from_message(msg)
|
44
|
+
version, # The version frame, which SHALL contain the three octets "1.0".
|
45
|
+
request_id, # The request id, which MAY contain an opaque binary blob.
|
46
|
+
domain, # The domain, which SHALL contain a string.
|
47
|
+
address, # The address, the origin network IP address.
|
48
|
+
identity, # The identity, the connection Identity, if any.
|
49
|
+
mechanism, # The mechanism, which SHALL contain a string.
|
50
|
+
*credentials = # The credentials, which SHALL be zero or more opaque frames.
|
51
|
+
msg.to_a
|
52
|
+
|
53
|
+
raise VersionMismatch if version != VERSION
|
54
|
+
|
55
|
+
new(domain, credentials, mechanism: mechanism).tap do |r|
|
56
|
+
r.version = version
|
57
|
+
r.request_id = request_id
|
58
|
+
r.address = address
|
59
|
+
r.identity = identity
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [String] ZAP version
|
64
|
+
attr_accessor :version
|
65
|
+
|
66
|
+
# @return [String, #to_s] the authentication domain
|
67
|
+
attr_accessor :domain
|
68
|
+
|
69
|
+
# @return [Array<String, #to_s>] the credentials, 0 or more
|
70
|
+
attr_accessor :credentials
|
71
|
+
|
72
|
+
# @return [String, #to_s]
|
73
|
+
attr_accessor :request_id
|
74
|
+
|
75
|
+
# @return [String, #to_s]
|
76
|
+
attr_accessor :address
|
77
|
+
|
78
|
+
# @return [String, #to_s] the connection identity
|
79
|
+
attr_accessor :identity
|
80
|
+
|
81
|
+
# @see Mechanisms
|
82
|
+
# @return [String, #to_s] the security mechanism to be used
|
83
|
+
attr_accessor :mechanism
|
84
|
+
|
85
|
+
# Initializes a new ZAP request. The security mechanism is set to
|
86
|
+
# CURVE (can be changed later).
|
87
|
+
#
|
88
|
+
# @param domain [String] the domain within to authenticate
|
89
|
+
# @param credentials [Array<String>] the credentials of the user,
|
90
|
+
# depending on the security mechanism used
|
91
|
+
def initialize(domain, credentials = [], mechanism: Mechanisms::CURVE)
|
92
|
+
@domain = domain
|
93
|
+
@credentials = credentials
|
94
|
+
@mechanism = mechanism
|
95
|
+
@version = VERSION
|
96
|
+
end
|
97
|
+
|
98
|
+
# Creates a sendable message from this {Request}.
|
99
|
+
# @return [CZTop::Message} this request packed into a message
|
100
|
+
def to_msg
|
101
|
+
fields = [ @version, @request_id, @domain, @address,
|
102
|
+
@identity, @mechanism, @credentials].flatten.map(&:to_s)
|
103
|
+
|
104
|
+
CZTop::Message.new(fields)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Represents a ZAP response.
|
109
|
+
class Response
|
110
|
+
|
111
|
+
# used to indicate a temporary error
|
112
|
+
class TemporaryError < Error
|
113
|
+
end
|
114
|
+
|
115
|
+
# used to indicate an internal error of the authenticator
|
116
|
+
class InternalError < Error
|
117
|
+
end
|
118
|
+
|
119
|
+
# Status codes of ZAP responses.
|
120
|
+
module StatusCodes
|
121
|
+
SUCCESS = "200"
|
122
|
+
TEMPORARY_ERROR = "300"
|
123
|
+
AUTHENTICATION_FAILURE = "400"
|
124
|
+
INTERNAL_ERROR = "500"
|
125
|
+
|
126
|
+
ALL = [
|
127
|
+
SUCCESS,
|
128
|
+
TEMPORARY_ERROR,
|
129
|
+
AUTHENTICATION_FAILURE,
|
130
|
+
INTERNAL_ERROR
|
131
|
+
]
|
132
|
+
end
|
133
|
+
|
134
|
+
include StatusCodes
|
135
|
+
|
136
|
+
# Crafts a new {Response} from a message.
|
137
|
+
#
|
138
|
+
# @param msg [CZTop::message] the message
|
139
|
+
# @return [Response] the response
|
140
|
+
# @raise [VersionMismatch] if the message contains an unsupported version
|
141
|
+
# @raise [TemporaryError] if the status code indicates a temporary error
|
142
|
+
# @raise [InternalError] if the status code indicates an internal error,
|
143
|
+
# or the status code is invalid
|
144
|
+
def self.from_message(msg)
|
145
|
+
version, # The version frame, which SHALL contain the three octets "1.0".
|
146
|
+
request_id, # The request id, which MAY contain an opaque binary blob.
|
147
|
+
status_code, # The status code, which SHALL contain a string.
|
148
|
+
status_text, # The status text, which MAY contain a string.
|
149
|
+
user_id, # The user id, which SHALL contain a string.
|
150
|
+
meta_data = # The meta data, which MAY contain a blob.
|
151
|
+
msg.to_a
|
152
|
+
|
153
|
+
raise VersionMismatch if version != VERSION
|
154
|
+
|
155
|
+
case status_code
|
156
|
+
when SUCCESS, AUTHENTICATION_FAILURE
|
157
|
+
# valid codes, nothing to do
|
158
|
+
when TEMPORARY_ERROR
|
159
|
+
raise TemporaryError, status_text
|
160
|
+
when INTERNAL_ERROR
|
161
|
+
raise InternalError, status_text
|
162
|
+
else
|
163
|
+
raise InternalError, "invalid status code"
|
164
|
+
end
|
165
|
+
|
166
|
+
new(status_code).tap do |r|
|
167
|
+
r.version = version
|
168
|
+
r.request_id = request_id
|
169
|
+
r.status_code = status_code
|
170
|
+
r.status_text = status_text
|
171
|
+
r.user_id = user_id
|
172
|
+
r.meta_data = meta_data
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# @return [String] ZAP version
|
177
|
+
attr_accessor :version
|
178
|
+
|
179
|
+
# @return [String] the original request ID
|
180
|
+
attr_accessor :request_id
|
181
|
+
|
182
|
+
# @return [String] status code
|
183
|
+
# @see StatusCodes
|
184
|
+
attr_accessor :status_code
|
185
|
+
|
186
|
+
# @return [String] status explanation
|
187
|
+
attr_accessor :status_text
|
188
|
+
|
189
|
+
# @return [String] meta data in ZMTP 3.0 format
|
190
|
+
attr_writer :meta_data
|
191
|
+
|
192
|
+
# @return [String] the user ID
|
193
|
+
attr_writer :user_id
|
194
|
+
|
195
|
+
# Initializes a new response.
|
196
|
+
#
|
197
|
+
# @param status_code [String, #to_s] ZAP status code
|
198
|
+
def initialize(status_code)
|
199
|
+
@status_code = status_code.to_s
|
200
|
+
raise ArgumentError unless ALL.include?(@status_code)
|
201
|
+
@version = VERSION
|
202
|
+
end
|
203
|
+
|
204
|
+
# @return [Boolean] whether the authentication was successful
|
205
|
+
def success?
|
206
|
+
@status_code == SUCCESS
|
207
|
+
end
|
208
|
+
|
209
|
+
# Returns the user ID, if authentication was successful.
|
210
|
+
# @return [String] the user ID of the authenticated user
|
211
|
+
# @return [nil] if authentication was unsuccessful
|
212
|
+
def user_id
|
213
|
+
return nil unless success?
|
214
|
+
@user_id
|
215
|
+
end
|
216
|
+
|
217
|
+
# Returns the meta data, if authentication was successful.
|
218
|
+
# @return [String] the meta data for the authenticated user
|
219
|
+
# @return [nil] if authentication was unsuccessful
|
220
|
+
def meta_data
|
221
|
+
return nil unless success?
|
222
|
+
@meta_data
|
223
|
+
end
|
224
|
+
|
225
|
+
# Creates a sendable message from this {Response}.
|
226
|
+
# @return [CZTop::Message} this request packed into a message
|
227
|
+
def to_msg
|
228
|
+
fields = [@version, @request_id, @status_code,
|
229
|
+
@status_text, @user_id, @meta_data].map(&:to_s)
|
230
|
+
CZTop::Message.new(fields)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
data/lib/cztop/zsock_options.rb
CHANGED
data/lib/cztop.rb
CHANGED
@@ -16,6 +16,7 @@ require_relative 'cztop/actor'
|
|
16
16
|
require_relative 'cztop/authenticator'
|
17
17
|
require_relative 'cztop/beacon'
|
18
18
|
require_relative 'cztop/certificate'
|
19
|
+
require_relative 'cztop/cert_store'
|
19
20
|
require_relative 'cztop/config'
|
20
21
|
require_relative 'cztop/frame'
|
21
22
|
require_relative 'cztop/message'
|
@@ -33,6 +34,7 @@ require_relative 'cztop/message/frames'
|
|
33
34
|
require_relative 'cztop/socket/types'
|
34
35
|
require_relative 'cztop/z85/padded'
|
35
36
|
require_relative 'cztop/z85/pipe'
|
37
|
+
require_relative 'cztop/zap'
|
36
38
|
|
37
39
|
|
38
40
|
# make Ctrl-C work in case a low-level call hangs
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cztop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrik Wenger
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: czmq-ffi-gen
|
@@ -251,6 +251,7 @@ files:
|
|
251
251
|
- lib/cztop/actor.rb
|
252
252
|
- lib/cztop/authenticator.rb
|
253
253
|
- lib/cztop/beacon.rb
|
254
|
+
- lib/cztop/cert_store.rb
|
254
255
|
- lib/cztop/certificate.rb
|
255
256
|
- lib/cztop/config.rb
|
256
257
|
- lib/cztop/config/comments.rb
|
@@ -271,6 +272,7 @@ files:
|
|
271
272
|
- lib/cztop/z85.rb
|
272
273
|
- lib/cztop/z85/padded.rb
|
273
274
|
- lib/cztop/z85/pipe.rb
|
275
|
+
- lib/cztop/zap.rb
|
274
276
|
- lib/cztop/zsock_options.rb
|
275
277
|
- perf/README.md
|
276
278
|
- perf/inproc_lat.rb
|