Ravn::Tactical::Auth::

PublicKeyScheme module

Implementation of bearer authentication using the keypairs of the kit’s nodes instead of a shared secret.

Constants

TOKEN_PATTERN

The format of a valid bearer auth token

Public Class Methods

authenticate_header( **options )

Make a valid WWW-Authenticate header for this kind of authentication.

   # File lib/ravn/tactical/auth/public_key_scheme.rb
31 def self::authenticate_header( **options )
32     realm = options[:realm] or raise "can't make a WWW-Authenticate header without a realm"
33     return "Pubkey realm=%p" % [ realm ]
34 end
authentication_failure( reason )

Convenience method for logging a reason authentication failed before returning nil.

    # File lib/ravn/tactical/auth/public_key_scheme.rb
121 def self::authentication_failure( reason )
122     self.log.error "Authentication failure: %s" % [ reason ]
123     return nil
124 end
authorization_failure( reason )

Convenience method for logging a reason authorization failed before returning nil.

    # File lib/ravn/tactical/auth/public_key_scheme.rb
128 def self::authorization_failure( reason )
129     self.log.error "Authorization failure: %s" % [ reason ]
130     return nil
131 end
check_auth_claims( ciphertext, node, request, **options )

Decrypt the token from the provided ciphertext using the given node‘s public key and check that the claims match the given request. Returns true if the token decrypts and its claims match, otherwise return nil after logging at error level.

    # File lib/ravn/tactical/auth/public_key_scheme.rb
 92 def self::check_auth_claims( ciphertext, node, request, **options )
 93     secret_key = options[:secret_key] || Ravn::Crypto.key
 94     claims = Ravn::Tactical::Auth.
 95         decode_token( ciphertext, node.public_key, secret_key: secret_key ) or
 96             return authentication_failure( 'Token could not be decoded.' )
 97 
 98     self.log.debug "Token claims: %p" % [ claims ]
 99     return authentication_failure( 'Token claims is not a Hash' ) unless claims.is_a?( Hash )
100 
101     claimed_control = claims[ :req ] or
102         return authentication_failure( 'Token claims is missing required element `req`.' )
103     request_control = "%s %s %s" % [
104         request.request_method,
105         request.fullpath,
106         request.get_header('SERVER_PROTOCOL')
107     ]
108     unless request_control == claimed_control
109         return authentication_failure 'Req claim %p does not match %p' %
110             [ claimed_control, request_control ]
111     end
112 
113     # :TODO: Check expiration claim after clocks are reliable
114 
115     return true
116 end
check_auth_credentials( credentials, request, ** )

Validate the auth credentials against the incoming request and return the device_id and encrypted token if successful. Returns nil after logging at error level if there’s a problem.

   # File lib/ravn/tactical/auth/public_key_scheme.rb
74 def self::check_auth_credentials( credentials, request, ** )
75     self.log.info "Checking authentication for %s: %p" % [ request.url, credentials ]
76     auth_token = credentials[:auth_token] or return authentication_failure( 'No auth token' )
77 
78     device_id, ciphertext = auth_token.split( '.' )
79     return authentication_failure( 'Token has no device ID' ) unless
80         device_id && !device_id.empty?
81     return authentication_failure( 'Token has no ciphertext' ) unless
82         ciphertext && !ciphertext.empty?
83 
84     return device_id, ciphertext
85 end
check_authentication( credentials, request, **options )

Check the authentication for request provided by the given credentials. Returns the authenticaated Ravn::Tactical::Node on success, nil on failure.

   # File lib/ravn/tactical/auth/public_key_scheme.rb
49 def self::check_authentication( credentials, request, **options )
50     device_id, ciphertext = self.check_auth_credentials( credentials, request, **options )
51     return nil unless device_id
52     node = Ravn::Tactical::Node.undeleted.by_device_id( device_id ).first or
53         return authentication_failure 'No such node %s' % [ device_id ]
54 
55     self.check_auth_claims( ciphertext, node, request, **options ) or return nil
56 
57     return node
58 end
check_authorization( identity, request, **options )

Check the authorization for the given request to ensure the provided identity should be able to access the resource. Returns true if it is authorized.

   # File lib/ravn/tactical/auth/public_key_scheme.rb
63 def self::check_authorization( identity, request, **options )
64     self.log.info "Checking authorization for %s: %p" % [ request.url, identity ]
65     return authorization_failure( "identity is not a node" ) unless identity.respond_to?( :is_control? )
66     return authorization_failure( "node is not the Control" ) unless identity.is_control?
67     return true
68 end
valid?( credentials, request, **options )

Returns true if this scheme can be used to authenticate the given request and options.

   # File lib/ravn/tactical/auth/public_key_scheme.rb
39 def self::valid?( credentials, request, **options )
40     self.log.debug "validating the public key auth for credentials: %p" % [ credentials ]
41     credentials[:auth_scheme] == 'Bearer' &&
42         credentials[:auth_token] &&
43         credentials[:auth_token].match?( TOKEN_PATTERN )
44 end