cztop 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|