gsasl 0.2.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.
- data/.travis.yml +9 -1
- data/README.md +1 -1
- data/lib/gsasl.rb +7 -4
- data/lib/gsasl/native.rb +11 -5
- data/lib/gsasl/peer.rb +32 -2
- data/lib/gsasl/version.rb +1 -1
- data/spec/peer_spec.rb +88 -0
- metadata +2 -2
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# GNU SASL for Ruby
|
1
|
+
# GNU SASL for Ruby [](http://travis-ci.org/threez/gsasl)
|
2
2
|
|
3
3
|
This libaray is a lib ffi based wrapper for the [GNU SASL](http://www.gnu.org/software/gsasl/) library. It supports a variaty of different authentication mechanisms. Those are the mechanisms supported for the current versions:
|
4
4
|
|
data/lib/gsasl.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
require "gsasl/version"
|
2
2
|
require "gsasl/native"
|
3
|
-
require "gsasl/context"
|
4
|
-
require "gsasl/remote_authenticator"
|
5
|
-
require "gsasl/peer"
|
6
3
|
|
7
4
|
module Gsasl
|
8
|
-
|
5
|
+
autoload :Context, "gsasl/context"
|
6
|
+
autoload :RemoteAuthenticator, "gsasl/remote_authenticator"
|
7
|
+
autoload :Peer, "gsasl/peer"
|
8
|
+
|
9
|
+
class GsaslError < StandardError;
|
10
|
+
attr_accessor :code
|
11
|
+
end
|
9
12
|
end
|
data/lib/gsasl/native.rb
CHANGED
@@ -2,7 +2,11 @@ require 'ffi'
|
|
2
2
|
|
3
3
|
module Gsasl
|
4
4
|
extend FFI::Library
|
5
|
-
|
5
|
+
begin
|
6
|
+
ffi_lib "libgsasl"
|
7
|
+
rescue LoadError # debain/ubuntu has a different name for the libgsasl library
|
8
|
+
ffi_lib "libgsasl.so.7"
|
9
|
+
end
|
6
10
|
|
7
11
|
# RFC 2222: SASL mechanisms are named by strings, from 1 to 20
|
8
12
|
# characters in length, consisting of upper-case letters, digits,
|
@@ -133,11 +137,13 @@ module Gsasl
|
|
133
137
|
attach_function :gsasl_step64, [ :pointer, :string, :pointer], :int
|
134
138
|
|
135
139
|
# Raises an error if the passed result is not GSASL_OK
|
136
|
-
# @param [Fixnum]
|
140
|
+
# @param [Fixnum] code that should be checked
|
137
141
|
# @raises [GsaslError] if a different result occured
|
138
|
-
def self.raise_error!(
|
139
|
-
if
|
140
|
-
|
142
|
+
def self.raise_error!(code)
|
143
|
+
if code != GSASL_OK
|
144
|
+
error = GsaslError.new(Gsasl.gsasl_strerror(code) + " [#{code}]")
|
145
|
+
error.code = code
|
146
|
+
raise error
|
141
147
|
end
|
142
148
|
end
|
143
149
|
|
data/lib/gsasl/peer.rb
CHANGED
@@ -156,7 +156,9 @@ module Gsasl
|
|
156
156
|
when Gsasl::GSASL_VALIDATE_SECURID
|
157
157
|
handle_secureid_authentication(&block)
|
158
158
|
when Gsasl::GSASL_DIGEST_MD5_HASHED_PASSWORD
|
159
|
-
handle_digest_md5_authentication(&block)
|
159
|
+
handle_digest_md5_authentication(&block) ||
|
160
|
+
# fallback to password if there is no hash digest available
|
161
|
+
handle_password_authentication(&block)
|
160
162
|
when Gsasl::GSASL_VALIDATE_ANONYMOUS
|
161
163
|
handle_anonymous_authentication(&block)
|
162
164
|
when Gsasl::GSASL_VALIDATE_EXTERNAL
|
@@ -260,6 +262,8 @@ module Gsasl
|
|
260
262
|
end
|
261
263
|
|
262
264
|
result == Gsasl::GSASL_OK
|
265
|
+
rescue GsaslError => ex
|
266
|
+
false
|
263
267
|
end
|
264
268
|
|
265
269
|
# Authenticate against a remote peer using a socket like authenication
|
@@ -291,6 +295,32 @@ module Gsasl
|
|
291
295
|
result == Gsasl::GSASL_OK
|
292
296
|
end
|
293
297
|
|
298
|
+
# Handles a client authentication request by the server peer.
|
299
|
+
# @param [String] client_initialization if the client already gives
|
300
|
+
# initialization data before the process starts
|
301
|
+
# @example
|
302
|
+
# auth_result = server.handle do |remote|
|
303
|
+
# remote.recieve { io.gets.strip }
|
304
|
+
# remote.send { |data| io.print "+ #{data}\r\n" }
|
305
|
+
# end
|
306
|
+
def handle(client_initialization = nil, &block)
|
307
|
+
result = GSASL_NEEDS_MORE
|
308
|
+
input = client_initialization
|
309
|
+
|
310
|
+
# create a new authenticator and define its behaviour
|
311
|
+
remote = RemoteAuthenticator.new
|
312
|
+
block.call(remote)
|
313
|
+
|
314
|
+
while result == GSASL_NEEDS_MORE
|
315
|
+
# use the client initialization if given (once) otherwise receive
|
316
|
+
# from the remote client
|
317
|
+
result, response = process input
|
318
|
+
input = remote.send(response) if result == GSASL_NEEDS_MORE
|
319
|
+
end
|
320
|
+
|
321
|
+
result == Gsasl::GSASL_OK
|
322
|
+
end
|
323
|
+
|
294
324
|
# Close the authentication peer. This should be done after one
|
295
325
|
# authenticaion.
|
296
326
|
def close
|
@@ -307,7 +337,7 @@ module Gsasl
|
|
307
337
|
output = output_ptr.get_pointer(0)
|
308
338
|
[result, output.read_string.to_s]
|
309
339
|
else
|
310
|
-
|
340
|
+
Gsasl.raise_error!(result)
|
311
341
|
end
|
312
342
|
ensure
|
313
343
|
Gsasl.gsasl_free(output)
|
data/lib/gsasl/version.rb
CHANGED
data/spec/peer_spec.rb
CHANGED
@@ -79,6 +79,94 @@ describe Gsasl::Context do
|
|
79
79
|
"fb2441a715a5484c6fa16147c4a6b7a8"
|
80
80
|
end
|
81
81
|
end
|
82
|
+
|
83
|
+
context "client authenticaten" do
|
84
|
+
before(:each) do
|
85
|
+
@general_handler = lambda do |server, client|
|
86
|
+
server.handle do |remote|
|
87
|
+
remote.send do |data|
|
88
|
+
_, output = client.process data
|
89
|
+
output
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should handle LOGIN" do
|
96
|
+
@client = @session.create_client("LOGIN")
|
97
|
+
@client.credentials!("joe", "secret")
|
98
|
+
@peer = @session.create_server("LOGIN") do |type, authid|
|
99
|
+
"secret" if type == :password && authid == "joe"
|
100
|
+
end
|
101
|
+
@general_handler.call(@peer, @client).should be_true
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should handle PLAIN" do
|
105
|
+
@client = @session.create_client("PLAIN")
|
106
|
+
@client.credentials!("joe", "secret")
|
107
|
+
@peer = @session.create_server("PLAIN") do |type, authid|
|
108
|
+
"secret" if type == :password && authid == "joe"
|
109
|
+
end
|
110
|
+
@general_handler.call(@peer, @client).should be_true
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should handle CRAM-MD5" do
|
114
|
+
@client = @session.create_client("CRAM-MD5")
|
115
|
+
@client.credentials!("joe", "secret")
|
116
|
+
@peer = @session.create_server("CRAM-MD5") do |type, authid|
|
117
|
+
"secret" if type == :password && authid == "joe"
|
118
|
+
end
|
119
|
+
@general_handler.call(@peer, @client).should be_true
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should handle SCRAM-SHA-1" do
|
123
|
+
@client = @session.create_client("SCRAM-SHA-1")
|
124
|
+
@client.credentials!("joe", "secret")
|
125
|
+
@peer = @session.create_server("SCRAM-SHA-1") do |type, authid|
|
126
|
+
"secret" if type == :password && authid == "joe"
|
127
|
+
end
|
128
|
+
@general_handler.call(@peer, @client).should be_true
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should handle DIGEST-MD5" do
|
132
|
+
@client = @session.create_client("DIGEST-MD5")
|
133
|
+
@client.credentials!("joe", "secret")
|
134
|
+
@client.service!("smtp", "localhost")
|
135
|
+
@client.realm = "gsasl"
|
136
|
+
@peer = @session.create_server("DIGEST-MD5", "gsasl") do |type, authid|
|
137
|
+
"secret" if type == :password && authid == "joe"
|
138
|
+
end
|
139
|
+
@general_handler.call(@peer, @client).should be_true
|
140
|
+
end
|
141
|
+
|
142
|
+
after(:each) do
|
143
|
+
@peer.close
|
144
|
+
@client.close
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context "client initialization" do
|
149
|
+
it "should be possible with PLAIN" do
|
150
|
+
@client = @session.create_client("PLAIN")
|
151
|
+
@client.credentials!("joe", "secret")
|
152
|
+
@peer = @session.create_server("PLAIN") do |type, authid|
|
153
|
+
"secret" if type == :password && authid == "joe"
|
154
|
+
end
|
155
|
+
_, init = @client.process # emulate a client side authentication
|
156
|
+
init.should_not be_empty
|
157
|
+
@peer.handle(init) do |remote|
|
158
|
+
remote.send do |data|
|
159
|
+
_, output = @client.process data
|
160
|
+
output
|
161
|
+
end
|
162
|
+
end.should be_true
|
163
|
+
end
|
164
|
+
|
165
|
+
after(:each) do
|
166
|
+
@peer.close
|
167
|
+
@client.close
|
168
|
+
end
|
169
|
+
end
|
82
170
|
|
83
171
|
after(:each) do
|
84
172
|
@session.close
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gsasl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-
|
12
|
+
date: 2012-05-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|