zas-service 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/zas/authenticators/filtered_authenticator.rb +8 -5
- data/lib/zas/authenticators/sequel_password_authenticator.rb +10 -4
- data/lib/zas/crypto_providers/sha512.rb +11 -6
- data/lib/zas/filters/http_basic_auth.rb +2 -2
- data/lib/zas/filters/standard_auth.rb +7 -1
- data/lib/zas/service.rb +11 -6
- metadata +1 -1
@@ -1,6 +1,6 @@
|
|
1
1
|
module Zas
|
2
2
|
module Authenticators
|
3
|
-
# An authenticator that filters the credentials through 1 or more filters that can transform
|
3
|
+
# Public: An authenticator that filters the credentials through 1 or more filters that can transform
|
4
4
|
# the credentials before passing them to another authenticator.
|
5
5
|
#
|
6
6
|
# Example:
|
@@ -10,7 +10,7 @@ module Zas
|
|
10
10
|
class FilteredAuthenticator
|
11
11
|
attr_accessor :logger
|
12
12
|
|
13
|
-
# Initialize the filtered authenticator with the given delegate
|
13
|
+
# Public: Initialize the filtered authenticator with the given delegate
|
14
14
|
# and filters. Filters will be applied when the authentication
|
15
15
|
# occurs.
|
16
16
|
#
|
@@ -21,13 +21,16 @@ module Zas
|
|
21
21
|
self.filters = [filters].compact.flatten
|
22
22
|
end
|
23
23
|
|
24
|
-
# Authenticate the given credentials.
|
24
|
+
# Public: Authenticate the given credentials.
|
25
25
|
#
|
26
26
|
# credentials - The credentials
|
27
|
+
#
|
28
|
+
# Returns true if the credentials are authenticated
|
27
29
|
def authenticate(credentials)
|
28
|
-
logger.info "Applying filters to credentials: #{filters.join(', ')}"
|
30
|
+
logger.info "Applying filters to credentials: #{filters.join(', ')}" if logger
|
29
31
|
credentials = filters.reduce(credentials) { |credentials, filter| filter.authenticate(credentials) }
|
30
|
-
logger.info "Delegating to #{delegate.class.name}"
|
32
|
+
logger.info "Delegating to #{delegate.class.name}" if logger
|
33
|
+
delegate.logger ||= logger
|
31
34
|
delegate.authenticate(*credentials)
|
32
35
|
end
|
33
36
|
|
@@ -30,9 +30,10 @@ module Zas
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
# Public: a logger.
|
33
34
|
attr_accessor :logger
|
34
35
|
|
35
|
-
# Initialize the autenticator with the given sequel DB. Optionally pass in additional
|
36
|
+
# Public: Initialize the autenticator with the given sequel DB. Optionally pass in additional
|
36
37
|
# configuration for the authenticator.
|
37
38
|
#
|
38
39
|
# sequel_db - The Sequel Datbase instance
|
@@ -45,11 +46,16 @@ module Zas
|
|
45
46
|
self.salt_field = config.salt_field.to_sym
|
46
47
|
end
|
47
48
|
|
48
|
-
# Authenticate the given username/password pair
|
49
|
+
# Public: Authenticate the given username/password pair
|
50
|
+
#
|
51
|
+
# username - The username
|
52
|
+
# password - The password
|
53
|
+
#
|
54
|
+
# Returns true if the username/password pair are authenticated. Will return a falsey value otherwise.
|
49
55
|
def authenticate(username, password)
|
50
|
-
logger.info "Authenticating #{username} (table: #{table_name}, username_field: #{username_field})"
|
56
|
+
logger.info "Authenticating #{username} (table: #{table_name}, username_field: #{username_field})" if logger
|
51
57
|
record = db[table_name].filter(username_field => username).first
|
52
|
-
logger.info "Record found for #{username}"
|
58
|
+
logger.info "Record found for #{username}" if logger
|
53
59
|
tokens = [password, record[salt_field]].compact
|
54
60
|
matches?(record[password_field], *tokens) if record
|
55
61
|
end
|
@@ -1,25 +1,30 @@
|
|
1
1
|
module Zas
|
2
2
|
module CryptoProviders
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Uses the Sha512 hash algorithm to encrypt passwords.
|
3
|
+
# Public: Uses the Sha512 hash algorithm to encrypt passwords.
|
6
4
|
class Sha512
|
7
5
|
require 'digest/sha2'
|
8
6
|
|
9
|
-
# The number of times to loop through the encryption. This is twenty because that is what restful_authentication defaults to.
|
7
|
+
# Public: The number of times to loop through the encryption. This is twenty because that is what restful_authentication defaults to.
|
10
8
|
def stretches
|
11
9
|
@stretches ||= 20
|
12
10
|
end
|
13
11
|
attr_writer :stretches
|
14
12
|
|
15
|
-
# Turns your raw password into a Sha512 hash.
|
13
|
+
# Public: Turns your raw password into a Sha512 hash.
|
14
|
+
#
|
15
|
+
# tokens - The tokens to encrypt
|
16
|
+
#
|
17
|
+
# Returns the encrypted string
|
16
18
|
def encrypt(*tokens)
|
17
19
|
digest = tokens.flatten.join(nil)
|
18
20
|
stretches.times { digest = Digest::SHA512.hexdigest(digest) }
|
19
21
|
digest
|
20
22
|
end
|
21
23
|
|
22
|
-
# Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
|
24
|
+
# Public: Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
|
25
|
+
#
|
26
|
+
# crytped - The crypted value
|
27
|
+
# tokens - A collection of tokens to encrypt
|
23
28
|
def matches?(crypted, *tokens)
|
24
29
|
encrypt(*tokens) == crypted
|
25
30
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'base64'
|
2
2
|
module Zas
|
3
3
|
module Filters
|
4
|
-
# Filter that base64 decodes the credentials and splits them
|
4
|
+
# Public: Filter that base64 decodes the credentials and splits them
|
5
5
|
# on a colon (based on the HTTP Basic Authentication
|
6
6
|
# speciications).
|
7
7
|
module HttpBasicAuth
|
8
8
|
module_function
|
9
|
-
# Filter the authentication credentials.
|
9
|
+
# Public: Filter the authentication credentials.
|
10
10
|
#
|
11
11
|
# credentials - The credentials
|
12
12
|
#
|
@@ -1,8 +1,14 @@
|
|
1
1
|
module Zas
|
2
2
|
module Filters
|
3
|
+
# Filter that converts from a Hash to an Array.
|
3
4
|
module StandardAuth
|
4
5
|
module_function
|
5
|
-
|
6
|
+
# Filter the authentication credentials by converting from
|
7
|
+
# a Hash to an array.
|
8
|
+
#
|
9
|
+
# credentials - The credentials Hash
|
10
|
+
#
|
11
|
+
# Returns a pair of [username, password]
|
6
12
|
def authenticate(credentials)
|
7
13
|
[credentials['username'], credentials['password']]
|
8
14
|
end
|
data/lib/zas/service.rb
CHANGED
@@ -4,7 +4,7 @@ require 'yajl'
|
|
4
4
|
require 'hashie'
|
5
5
|
|
6
6
|
module Zas
|
7
|
-
# Authentication service class. Construct a new instance of this
|
7
|
+
# Public: Authentication service class. Construct a new instance of this
|
8
8
|
# class and call the instance method #run to start it.
|
9
9
|
class Service
|
10
10
|
require 'zas/service_configuration'
|
@@ -12,14 +12,17 @@ module Zas
|
|
12
12
|
require 'zas/authenticators'
|
13
13
|
require 'zas/crypto_providers'
|
14
14
|
|
15
|
+
# Public: A syslog logger
|
15
16
|
attr_accessor :logger
|
16
17
|
|
17
|
-
# A collection authenticators mapped to keys.
|
18
|
+
# Public: A collection authenticators mapped to keys.
|
19
|
+
#
|
20
|
+
# Returns a Hash of authenticators.
|
18
21
|
def authenticators
|
19
22
|
@authenticators ||= {}
|
20
23
|
end
|
21
24
|
|
22
|
-
# Initialize the service. The service will not be running yet. Invoke the #run method on the service
|
25
|
+
# Public: Initialize the service. The service will not be running yet. Invoke the #run method on the service
|
23
26
|
# instantce to run the service.
|
24
27
|
#
|
25
28
|
# config - Configuration spec for the service.
|
@@ -30,7 +33,8 @@ module Zas
|
|
30
33
|
self.logger = Syslogger.new(config.name, Syslog::LOG_PID, Syslog::LOG_LOCAL0)
|
31
34
|
end
|
32
35
|
|
33
|
-
# Run the service.
|
36
|
+
# Public: Run the service. This method will block while awaiting incoming requests. The service
|
37
|
+
# may be stopped by sending the INT signal.
|
34
38
|
def run
|
35
39
|
socket = context.socket ZMQ::REP
|
36
40
|
socket.bind "tcp://#{host}:#{port}"
|
@@ -54,7 +58,7 @@ module Zas
|
|
54
58
|
attr_accessor :context
|
55
59
|
attr_writer :logger
|
56
60
|
|
57
|
-
# Handle the authentication.
|
61
|
+
# Internal: Handle the authentication.
|
58
62
|
#
|
59
63
|
# req_string - A JSON string
|
60
64
|
#
|
@@ -63,13 +67,14 @@ module Zas
|
|
63
67
|
req = Hashie::Mash.new(Yajl::Parser.parse(req_string))
|
64
68
|
authenticator = authenticators[req.strategy]
|
65
69
|
raise "No authenticator found for #{req.strategy}" unless authenticator
|
70
|
+
authenticator.logger ||= logger
|
66
71
|
{:authenticated? => authenticator.authenticate(req.credentials)}
|
67
72
|
rescue => e
|
68
73
|
logger.info "Error authenticating: #{e.message}"
|
69
74
|
{:error => e.message}
|
70
75
|
end
|
71
76
|
|
72
|
-
# Encode the response object
|
77
|
+
# Internal: Encode the response object
|
73
78
|
#
|
74
79
|
# data - The object
|
75
80
|
#
|