Class: OpenNebula::X509Auth

Inherits:
Object
  • Object
show all
Defined in:
lib/opennebula/x509_auth.rb

Overview

X509 authentication class. It can be used as a driver for auth_mad as auth method is defined. It also holds some helper methods to be used by oneauth command

Direct Known Subclasses

ServerX509Auth

Constant Summary collapse

ETC_LOCATION =
ENV["ONE_LOCATION"] + "/etc"
X509_AUTH_CONF_PATH =
ETC_LOCATION + "/auth/x509_auth.conf"
X509_DEFAULTS =
{
    :ca_dir   => ETC_LOCATION + "/auth/certificates"
}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ X509Auth

Initialize x509Auth object

Parameters:

  • default (Hash)

    options for path

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :certs_pem (String)

    cert chain array in colon-separated pem format

  • :key_pem (String)

    key in pem format

  • :ca_dir (String)

    directory of trusted CA’s. Needed for auth method, not for login.



61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/opennebula/x509_auth.rb', line 61

def initialize(options={})
    @options ||= X509_DEFAULTS
    @options.merge!(options)

    load_options(X509_AUTH_CONF_PATH)

    @cert_chain = @options[:certs_pem].collect do |cert_pem|
        OpenSSL::X509::Certificate.new(cert_pem)
    end

    if @options[:key_pem]
        @key  = OpenSSL::PKey::RSA.new(@options[:key_pem])
    end
end

Class Method Details

.escape_dn(dn) ⇒ Object



43
44
45
# File 'lib/opennebula/x509_auth.rb', line 43

def self.escape_dn(dn)
    dn.gsub(/\s/) { |s| "\\"+s[0].ord.to_s(16) }
end

.unescape_dn(dn) ⇒ Object



47
48
49
# File 'lib/opennebula/x509_auth.rb', line 47

def self.unescape_dn(dn)
    dn.gsub(/\\[0-9a-f]{2}/) { |s| s[1,2].to_i(16).chr }
end

Instance Method Details

#authenticate(user, pass, signed_text) ⇒ Object

Server side

auth method for auth_mad



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/opennebula/x509_auth.rb', line 112

def authenticate(user, pass, signed_text)
    begin
        # Decryption demonstrates that the user posessed the private key.
        _user, expires = decrypt(signed_text).split(':')

        return "User name missmatch" if user != _user

        return "x509 proxy expired"  if Time.now.to_i >= expires.to_i

        # Some DN in the chain must match a DN in the password
        dn_ok = @cert_chain.each do |cert|
            if pass.split('|').include?(
                    self.class.escape_dn(cert.subject.to_s))
                break true
            end
        end

        unless dn_ok == true
            return "Certificate subject missmatch"
        end

        validate

        return true
    rescue => e
        return e.message
    end
end

#login_token(user, expire = 0) ⇒ Object

Generates a login token in the form: user_name:x509:user_name:time_expires:cert_chain

- user_name:time_expires is encrypted with the user certificate
- user_name:time_expires:cert_chain is base64 encoded.

By default it is valid as long as the certificate is valid. It can be changed to any number of seconds with expire parameter (sec.)



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/opennebula/x509_auth.rb', line 92

def (user, expire=0)
    if expire != 0
        expires = Time.now.to_i + expire.to_i
    else
        expires = @cert_chain[0].not_after.to_i
    end

    text_to_sign = "#{user}:#{expires}"
    signed_text  = encrypt(text_to_sign)

    certs_pem = @cert_chain.collect{|cert| cert.to_pem}.join(":")
    token     = "#{signed_text}:#{certs_pem}"

    return Base64::encode64(token).strip.delete("\n")
end

#passwordObject

Returns a valid password string to create a user using this auth driver. In this case the dn of the user certificate.



82
83
84
# File 'lib/opennebula/x509_auth.rb', line 82

def password
    self.class.escape_dn(@cert_chain[0].subject.to_s)
end