opennebula-oca 3.8.0 → 3.9.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/lib/{OpenNebula/Acl.rb → opennebula/acl.rb} +0 -0
  2. data/lib/{OpenNebula/AclPool.rb → opennebula/acl_pool.rb} +1 -1
  3. data/lib/{OpenNebula.rb → opennebula/client.rb} +0 -73
  4. data/lib/{OpenNebula/Cluster.rb → opennebula/cluster.rb} +1 -1
  5. data/lib/{OpenNebula/ClusterPool.rb → opennebula/cluster_pool.rb} +1 -1
  6. data/lib/{OpenNebula/Datastore.rb → opennebula/datastore.rb} +23 -1
  7. data/lib/{OpenNebula/DatastorePool.rb → opennebula/datastore_pool.rb} +1 -1
  8. data/lib/{OpenNebula/Document.rb → opennebula/document.rb} +13 -2
  9. data/lib/{OpenNebula/DocumentJSON.rb → opennebula/document_json.rb} +0 -0
  10. data/lib/{OpenNebula/DocumentPool.rb → opennebula/document_pool.rb} +2 -2
  11. data/lib/{OpenNebula/DocumentPoolJSON.rb → opennebula/document_pool_json.rb} +0 -0
  12. data/lib/opennebula/error.rb +52 -0
  13. data/lib/{OpenNebula/Group.rb → opennebula/group.rb} +1 -1
  14. data/lib/{OpenNebula/GroupPool.rb → opennebula/group_pool.rb} +1 -1
  15. data/lib/{OpenNebula/Host.rb → opennebula/host.rb} +1 -1
  16. data/lib/{OpenNebula/HostPool.rb → opennebula/host_pool.rb} +1 -1
  17. data/lib/{OpenNebula/Image.rb → opennebula/image.rb} +20 -6
  18. data/lib/{OpenNebula/ImagePool.rb → opennebula/image_pool.rb} +1 -1
  19. data/lib/opennebula/ldap_auth.rb +99 -0
  20. data/lib/opennebula/ldap_auth_spec.rb +70 -0
  21. data/lib/opennebula/pool.rb +157 -0
  22. data/lib/{OpenNebula/Pool.rb → opennebula/pool_element.rb} +1 -138
  23. data/lib/opennebula/server_cipher_auth.rb +148 -0
  24. data/lib/opennebula/server_x509_auth.rb +104 -0
  25. data/lib/opennebula/ssh_auth.rb +139 -0
  26. data/lib/opennebula/system.rb +141 -0
  27. data/lib/{OpenNebula/Template.rb → opennebula/template.rb} +13 -2
  28. data/lib/{OpenNebula/TemplatePool.rb → opennebula/template_pool.rb} +1 -1
  29. data/lib/{OpenNebula/User.rb → opennebula/user.rb} +1 -1
  30. data/lib/{OpenNebula/UserPool.rb → opennebula/user_pool.rb} +1 -1
  31. data/lib/{OpenNebula/VirtualMachine.rb → opennebula/virtual_machine.rb} +45 -25
  32. data/lib/{OpenNebula/VirtualMachinePool.rb → opennebula/virtual_machine_pool.rb} +1 -1
  33. data/lib/{OpenNebula/VirtualNetwork.rb → opennebula/virtual_network.rb} +13 -2
  34. data/lib/{OpenNebula/VirtualNetworkPool.rb → opennebula/virtual_network_pool.rb} +1 -1
  35. data/lib/opennebula/x509_auth.rb +241 -0
  36. data/lib/{OpenNebula/XMLUtils.rb → opennebula/xml_element.rb} +12 -21
  37. data/lib/opennebula/xml_pool.rb +45 -0
  38. data/lib/opennebula/xml_utils.rb +34 -0
  39. data/lib/opennebula.rb +58 -0
  40. metadata +102 -63
@@ -0,0 +1,157 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+ require 'opennebula/xml_utils'
18
+
19
+ module OpenNebula
20
+
21
+ # The Pool class represents a generic OpenNebula Pool in XML format
22
+ # and provides the basic functionality to handle the Pool elements
23
+ class Pool < XMLPool
24
+ include Enumerable
25
+
26
+ protected
27
+ #pool:: _String_ XML name of the root element
28
+ #element:: _String_ XML name of the Pool elements
29
+ #client:: _Client_ represents a XML-RPC connection
30
+ def initialize(pool,element,client)
31
+ super(nil)
32
+
33
+ @pool_name = pool.upcase
34
+ @element_name = element.upcase
35
+
36
+ @client = client
37
+ end
38
+
39
+ # Default Factory Method for the Pools. The factory method returns an
40
+ # suitable PoolElement object. Each Pool MUST implement the
41
+ # corresponding factory method
42
+ # element_xml:: _XML_ XML element describing the pool element
43
+ # [return] a PoolElement object
44
+ def factory(element_xml)
45
+ OpenNebula::PoolElement.new(element_xml,client)
46
+ end
47
+
48
+ #######################################################################
49
+ # Common XML-RPC Methods for all the Pool Types
50
+ #######################################################################
51
+
52
+ #Gets the pool without any filter. Host, Group and User Pools
53
+ # xml_method:: _String_ the name of the XML-RPC method
54
+ def info(xml_method)
55
+ return xmlrpc_info(xml_method)
56
+ end
57
+
58
+ def info_all(xml_method, *args)
59
+ return xmlrpc_info(xml_method,INFO_ALL,-1,-1, *args)
60
+ end
61
+
62
+ def info_mine(xml_method, *args)
63
+ return xmlrpc_info(xml_method,INFO_MINE,-1,-1, *args)
64
+ end
65
+
66
+ def info_group(xml_method, *args)
67
+ return xmlrpc_info(xml_method,INFO_GROUP,-1,-1, *args)
68
+ end
69
+
70
+ def info_filter(xml_method, who, start_id, end_id, *args)
71
+ return xmlrpc_info(xml_method,who, start_id, end_id, *args)
72
+ end
73
+
74
+ # Retrieves the monitoring data for all the Objects in the pool
75
+ #
76
+ # @param [String] xml_method xml-rcp method
77
+ # @param [String] root_elem Root for each individual PoolElement
78
+ # @param [String] timestamp_elem Name of the XML element with the last
79
+ # monitorization timestamp
80
+ # @param [Array<String>] xpath_expressions Elements to retrieve.
81
+ # @param args arguemnts for the xml_method call
82
+ #
83
+ # @return [Hash<String, <Hash<String, Array<Array<int>>>>>,
84
+ # OpenNebula::Error] The first level hash uses the Object ID as keys,
85
+ # and as value a Hash with the requested xpath expressions,
86
+ # and an Array of 'timestamp, value'.
87
+ def monitoring(xml_method, root_elem, timestamp_elem, xpath_expressions,
88
+ *args)
89
+
90
+ rc = @client.call(xml_method, *args)
91
+
92
+ if ( OpenNebula.is_error?(rc) )
93
+ return rc
94
+ end
95
+
96
+ xmldoc = XMLElement.new
97
+ xmldoc.initialize_xml(rc, 'MONITORING_DATA')
98
+
99
+ hash = {}
100
+
101
+ # Get all existing Object IDs
102
+ ids = xmldoc.retrieve_elements("#{root_elem}/ID")
103
+
104
+ if ids.nil?
105
+ return hash
106
+ else
107
+ ids.uniq!
108
+ end
109
+
110
+ ids.each { |id|
111
+ hash[id] = OpenNebula.process_monitoring(
112
+ xmldoc, root_elem, timestamp_elem, id, xpath_expressions)
113
+
114
+ }
115
+
116
+ return hash
117
+ end
118
+
119
+ private
120
+ # Calls to the corresponding info method to retreive the pool
121
+ # representation in XML format
122
+ # xml_method:: _String_ the name of the XML-RPC method
123
+ # args:: _Array_ with additional arguments for the info call
124
+ # [return] nil in case of success or an Error object
125
+ def xmlrpc_info(xml_method,*args)
126
+ rc = @client.call(xml_method,*args)
127
+
128
+ if !OpenNebula.is_error?(rc)
129
+ initialize_xml(rc,@pool_name)
130
+ rc = nil
131
+ end
132
+
133
+ return rc
134
+ end
135
+
136
+ public
137
+ # Constants for info queries (include/RequestManagerPoolInfoFilter.h)
138
+ INFO_GROUP = -1
139
+ INFO_ALL = -2
140
+ INFO_MINE = -3
141
+
142
+ # Iterates over every PoolElement in the Pool and calls the block with a
143
+ # a PoolElement obtained calling the factory method
144
+ # block:: _Block_
145
+ def each(&block)
146
+ each_element(block) if @xml
147
+ end
148
+
149
+ # DO NOT USE - ONLY REXML BACKEND
150
+ def to_str
151
+ str = ""
152
+ REXML::Formatters::Pretty.new(1).write(@xml,str)
153
+
154
+ return str
155
+ end
156
+ end
157
+ end
@@ -14,146 +14,9 @@
14
14
  # limitations under the License. #
15
15
  #--------------------------------------------------------------------------- #
16
16
 
17
+ require 'opennebula/pool'
17
18
 
18
19
  module OpenNebula
19
-
20
- # The Pool class represents a generic OpenNebula Pool in XML format
21
- # and provides the basic functionality to handle the Pool elements
22
- class Pool < XMLPool
23
- include Enumerable
24
-
25
- protected
26
- #pool:: _String_ XML name of the root element
27
- #element:: _String_ XML name of the Pool elements
28
- #client:: _Client_ represents a XML-RPC connection
29
- def initialize(pool,element,client)
30
- super(nil)
31
-
32
- @pool_name = pool.upcase
33
- @element_name = element.upcase
34
-
35
- @client = client
36
- end
37
-
38
- # Default Factory Method for the Pools. The factory method returns an
39
- # suitable PoolElement object. Each Pool MUST implement the
40
- # corresponding factory method
41
- # element_xml:: _XML_ XML element describing the pool element
42
- # [return] a PoolElement object
43
- def factory(element_xml)
44
- OpenNebula::PoolElement.new(element_xml,client)
45
- end
46
-
47
- #######################################################################
48
- # Common XML-RPC Methods for all the Pool Types
49
- #######################################################################
50
-
51
- #Gets the pool without any filter. Host, Group and User Pools
52
- # xml_method:: _String_ the name of the XML-RPC method
53
- def info(xml_method)
54
- return xmlrpc_info(xml_method)
55
- end
56
-
57
- def info_all(xml_method, *args)
58
- return xmlrpc_info(xml_method,INFO_ALL,-1,-1, *args)
59
- end
60
-
61
- def info_mine(xml_method, *args)
62
- return xmlrpc_info(xml_method,INFO_MINE,-1,-1, *args)
63
- end
64
-
65
- def info_group(xml_method, *args)
66
- return xmlrpc_info(xml_method,INFO_GROUP,-1,-1, *args)
67
- end
68
-
69
- def info_filter(xml_method, who, start_id, end_id, *args)
70
- return xmlrpc_info(xml_method,who, start_id, end_id, *args)
71
- end
72
-
73
- # Retrieves the monitoring data for all the Objects in the pool
74
- #
75
- # @param [String] xml_method xml-rcp method
76
- # @param [String] root_elem Root for each individual PoolElement
77
- # @param [String] timestamp_elem Name of the XML element with the last
78
- # monitorization timestamp
79
- # @param [Array<String>] xpath_expressions Elements to retrieve.
80
- # @param args arguemnts for the xml_method call
81
- #
82
- # @return [Hash<String, <Hash<String, Array<Array<int>>>>>,
83
- # OpenNebula::Error] The first level hash uses the Object ID as keys,
84
- # and as value a Hash with the requested xpath expressions,
85
- # and an Array of 'timestamp, value'.
86
- def monitoring(xml_method, root_elem, timestamp_elem, xpath_expressions,
87
- *args)
88
-
89
- rc = @client.call(xml_method, *args)
90
-
91
- if ( OpenNebula.is_error?(rc) )
92
- return rc
93
- end
94
-
95
- xmldoc = XMLElement.new
96
- xmldoc.initialize_xml(rc, 'MONITORING_DATA')
97
-
98
- hash = {}
99
-
100
- # Get all existing Object IDs
101
- ids = xmldoc.retrieve_elements("#{root_elem}/ID")
102
-
103
- if ids.nil?
104
- return hash
105
- else
106
- ids.uniq!
107
- end
108
-
109
- ids.each { |id|
110
- hash[id] = OpenNebula.process_monitoring(
111
- xmldoc, root_elem, timestamp_elem, id, xpath_expressions)
112
-
113
- }
114
-
115
- return hash
116
- end
117
-
118
- private
119
- # Calls to the corresponding info method to retreive the pool
120
- # representation in XML format
121
- # xml_method:: _String_ the name of the XML-RPC method
122
- # args:: _Array_ with additional arguments for the info call
123
- # [return] nil in case of success or an Error object
124
- def xmlrpc_info(xml_method,*args)
125
- rc = @client.call(xml_method,*args)
126
-
127
- if !OpenNebula.is_error?(rc)
128
- initialize_xml(rc,@pool_name)
129
- rc = nil
130
- end
131
-
132
- return rc
133
- end
134
-
135
- public
136
- # Constants for info queries (include/RequestManagerPoolInfoFilter.h)
137
- INFO_GROUP = -1
138
- INFO_ALL = -2
139
- INFO_MINE = -3
140
-
141
- # Iterates over every PoolElement in the Pool and calls the block with a
142
- # a PoolElement obtained calling the factory method
143
- # block:: _Block_
144
- def each(&block)
145
- each_element(block) if @xml
146
- end
147
-
148
- # DO NOT USE - ONLY REXML BACKEND
149
- def to_str
150
- str = ""
151
- REXML::Formatters::Pretty.new(1).write(@xml,str)
152
-
153
- return str
154
- end
155
- end
156
-
157
20
  # The PoolElement Class represents a generic element of a Pool in
158
21
  # XML format
159
22
  class PoolElement < XMLElement
@@ -0,0 +1,148 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+ require 'openssl'
18
+ require 'digest/sha1'
19
+
20
+ require 'base64'
21
+ require 'fileutils'
22
+
23
+ module OpenNebula; end
24
+
25
+ # Server authentication class. This method can be used by OpenNebula services
26
+ # to let access authenticated users by other means. It is based on OpenSSL
27
+ # symmetric ciphers
28
+ class OpenNebula::ServerCipherAuth
29
+ ###########################################################################
30
+ #Constants with paths to relevant files and defaults
31
+ ###########################################################################
32
+
33
+ CIPHER = "aes-256-cbc"
34
+
35
+ ###########################################################################
36
+
37
+ def initialize(srv_user, srv_passwd)
38
+ @srv_user = srv_user
39
+ @srv_passwd = srv_passwd
40
+
41
+ if !srv_passwd.empty?
42
+ @key = Digest::SHA1.hexdigest(@srv_passwd)
43
+ else
44
+ @key = ""
45
+ end
46
+
47
+ @cipher = OpenSSL::Cipher::Cipher.new(CIPHER)
48
+ end
49
+
50
+ ###########################################################################
51
+ # Client side
52
+ ###########################################################################
53
+
54
+ # Creates a ServerCipher for client usage
55
+ def self.new_client(srv_user=nil, srv_passwd=nil)
56
+ if ( srv_user == nil || srv_passwd == nil )
57
+ begin
58
+ if ENV["ONE_CIPHER_AUTH"] and !ENV["ONE_CIPHER_AUTH"].empty?
59
+ one_auth = File.read(ENV["ONE_CIPHER_AUTH"])
60
+ else
61
+ raise "ONE_CIPHER_AUTH environment variable not set"
62
+ end
63
+
64
+ one_auth.rstrip!
65
+
66
+ rc = one_auth.match(/(.*?):(.*)/)
67
+
68
+ if rc.nil?
69
+ raise "Bad format for one_auth token (<user>:<passwd>)"
70
+ else
71
+ srv_user = rc[1]
72
+ srv_passwd = rc[2]
73
+ end
74
+ rescue => e
75
+ raise e.message
76
+ end
77
+ end
78
+
79
+ self.new(srv_user, srv_passwd)
80
+ end
81
+
82
+ # Generates a login token in the form:
83
+ # - server_user:target_user:time_expires
84
+ # The token is then encrypted with the contents of one_auth
85
+ def login_token(expire, target_user=nil)
86
+ target_user ||= @srv_user
87
+ token_txt = "#{@srv_user}:#{target_user}:#{expire}"
88
+
89
+ token = encrypt(token_txt)
90
+ token64 = Base64::encode64(token).strip.delete("\n")
91
+
92
+ return "#{@srv_user}:#{target_user}:#{token64}"
93
+ end
94
+
95
+ # Returns a valid password string to create a user using this auth driver
96
+ def password
97
+ return @srv_passwd
98
+ end
99
+
100
+ ###########################################################################
101
+ # Driver side
102
+ ###########################################################################
103
+
104
+ # Creates a ServerCipher for driver usage
105
+ def self.new_driver()
106
+ self.new("","")
107
+ end
108
+
109
+ # auth method for auth_mad
110
+ def authenticate(srv_user,srv_pass, signed_text)
111
+ begin
112
+ @key = srv_pass
113
+
114
+ s_user, t_user, expires = decrypt(signed_text).split(':')
115
+
116
+ return "User name missmatch" if s_user != srv_user
117
+
118
+ return "login token expired" if Time.now.to_i >= expires.to_i
119
+
120
+ return true
121
+ rescue => e
122
+ return e.message
123
+ end
124
+ end
125
+
126
+ private
127
+
128
+ def encrypt(data)
129
+ @cipher.encrypt
130
+ @cipher.key = @key
131
+
132
+ rc = @cipher.update(data)
133
+ rc << @cipher.final
134
+
135
+ return rc
136
+ end
137
+
138
+ def decrypt(data)
139
+ @cipher.decrypt
140
+ @cipher.key = @key
141
+
142
+ rc = @cipher.update(Base64::decode64(data))
143
+ rc << @cipher.final
144
+
145
+ return rc
146
+ end
147
+ end
148
+
@@ -0,0 +1,104 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+ require 'openssl'
18
+ require 'base64'
19
+ require 'fileutils'
20
+
21
+ require 'opennebula/x509_auth'
22
+
23
+ module OpenNebula; end
24
+
25
+ # Server authentication class. This authmethod can be used by opennebula services
26
+ # to let access authenticated users by other means. It is based on x509 server
27
+ # certificates
28
+ class OpenNebula::ServerX509Auth < OpenNebula::X509Auth
29
+ ###########################################################################
30
+ #Constants with paths to relevant files and defaults
31
+ ###########################################################################
32
+
33
+ SERVER_AUTH_CONF_PATH = ETC_LOCATION + "/auth/server_x509_auth.conf"
34
+
35
+ SERVER_DEFAULTS = {
36
+ :one_cert => ETC_LOCATION + "/auth/cert.pem",
37
+ :one_key => ETC_LOCATION + "/auth/key.pem"
38
+ }
39
+
40
+ ###########################################################################
41
+
42
+ def initialize()
43
+ @options = SERVER_DEFAULTS
44
+
45
+ load_options(SERVER_AUTH_CONF_PATH)
46
+
47
+ begin
48
+ certs = [ File.read(@options[:one_cert]) ]
49
+ key = File.read(@options[:one_key])
50
+
51
+ super(:certs_pem => certs, :key_pem => key)
52
+ rescue
53
+ raise
54
+ end
55
+
56
+ if @options[:srv_user] == nil || @options[:srv_user].empty?
57
+ raise "User for x509 server not defined"
58
+ end
59
+ end
60
+
61
+ ###########################################################################
62
+ # Client side
63
+ ###########################################################################
64
+
65
+ # Creates a ServerCipher for client and driver sage
66
+ class << OpenNebula::ServerX509Auth
67
+ alias :new_client :new
68
+ alias :new_driver :new
69
+ end
70
+
71
+ # Generates a login token in the form:
72
+ # - server_user:target_user:time_expires
73
+ def login_token(expire, target_user=nil)
74
+ target_user ||= @options[:srv_user]
75
+ token_txt = "#{@options[:srv_user]}:#{target_user}:#{expire}"
76
+
77
+ token = encrypt(token_txt)
78
+ token64 = Base64::encode64(token).strip.delete("\n")
79
+
80
+ return "#{@options[:srv_user]}:#{target_user}:#{token64}"
81
+ end
82
+
83
+ ###########################################################################
84
+ # Server side
85
+ ###########################################################################
86
+
87
+ # auth method for auth_mad
88
+ def authenticate(server_user, server_pass, signed_text)
89
+ begin
90
+ s_user, t_user, expires = decrypt(signed_text).split(':')
91
+
92
+ return "Server password missmatch" if server_pass != password
93
+
94
+ return "User name missmatch" if ( s_user != server_user ||
95
+ s_user != @options[:srv_user] )
96
+
97
+ return "login token expired" if Time.now.to_i >= expires.to_i
98
+
99
+ return true
100
+ rescue => e
101
+ return e.message
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,139 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+
18
+ require 'pp'
19
+ require 'openssl'
20
+ require 'base64'
21
+ require 'fileutils'
22
+
23
+ module OpenNebula; end
24
+
25
+ # SSH key authentication class. It can be used as a driver for auth_mad
26
+ # as auth method is defined. It also holds some helper methods to be used
27
+ # by oneauth command
28
+ class OpenNebula::SshAuth
29
+ LOGIN_PATH = ENV['HOME']+'/.one/one_ssh'
30
+
31
+ # Initialize SshAuth object
32
+ #
33
+ # @param [Hash] default options for path
34
+ # @option options [String] :public_key public key for the user
35
+ # @option options [String] :private_key key private key for the user.
36
+ def initialize(options={})
37
+ @private_key = nil
38
+ @public_key = nil
39
+
40
+ if options[:private_key]
41
+ begin
42
+ @private_key = File.read(options[:private_key])
43
+ rescue Exception => e
44
+ raise "Cannot read #{options[:private_key]}"
45
+ end
46
+ end
47
+
48
+ if options[:public_key]
49
+ @public_key = options[:public_key]
50
+ elsif @private_key != nil
51
+ # Init ssh keys using private key. public key is extracted in a
52
+ # format compatible with openssl. The public key does not contain
53
+ # "---- BEGIN/END RSA PUBLIC KEY ----" and is in a single line
54
+ key = OpenSSL::PKey::RSA.new(@private_key)
55
+
56
+ @public_key = key.public_key.to_pem.split("\n")
57
+ @public_key = @public_key.reject {|l| l.match(/RSA PUBLIC KEY/) }.join('')
58
+ end
59
+
60
+ if @private_key.nil? && @public_key.nil?
61
+ raise "You have to define at least one of the keys"
62
+ end
63
+ end
64
+
65
+ # Creates the login file for ssh authentication at ~/.one/one_ssh.
66
+ # By default it is valid for 1 hour but it can be changed to any number
67
+ # of seconds with expire parameter (in seconds)
68
+ def login(user, expire=3600)
69
+ expire ||= 3600
70
+
71
+ # Init proxy file path and creates ~/.one directory if needed
72
+ proxy_dir = File.dirname(LOGIN_PATH)
73
+
74
+ begin
75
+ FileUtils.mkdir_p(proxy_dir)
76
+ rescue Errno::EEXIST
77
+ end
78
+
79
+ # Generate security token
80
+ time = Time.now.to_i + expire.to_i
81
+
82
+ secret_plain = "#{user}:#{time}"
83
+ secret_crypted = encrypt(secret_plain)
84
+
85
+ proxy = "#{user}:#{secret_crypted}"
86
+
87
+ file = File.open(LOGIN_PATH, "w")
88
+ file.write(proxy)
89
+ file.close
90
+
91
+ File.chmod(0600,LOGIN_PATH)
92
+
93
+ secret_crypted
94
+ end
95
+
96
+ # Returns a valid password string to create a user using this auth driver.
97
+ # In this case the ssh public key.
98
+ def password
99
+ @public_key
100
+ end
101
+
102
+ # Checks the proxy created with the login method
103
+ def authenticate(user, token)
104
+ begin
105
+ token_plain = decrypt(token)
106
+ _user, time = token_plain.split(':')
107
+
108
+ if user == _user
109
+ if Time.now.to_i >= time.to_i
110
+ return "ssh proxy expired, login again to renew it"
111
+ else
112
+ return true
113
+ end
114
+ else
115
+ return "invalid credentials"
116
+ end
117
+ rescue
118
+ return "error"
119
+ end
120
+ end
121
+
122
+ private
123
+
124
+ ###########################################################################
125
+ # Methods to handle ssh keys
126
+ ###########################################################################
127
+ # Encrypts data with the private key of the user and returns
128
+ # base 64 encoded output in a single line
129
+ def encrypt(data)
130
+ rsa=OpenSSL::PKey::RSA.new(@private_key)
131
+ Base64::encode64(rsa.private_encrypt(data)).gsub!(/\n/, '').strip
132
+ end
133
+
134
+ # Decrypts base 64 encoded data with pub_key (public key)
135
+ def decrypt(data)
136
+ rsa=OpenSSL::PKey::RSA.new(Base64::decode64(@public_key))
137
+ rsa.public_decrypt(Base64::decode64(data))
138
+ end
139
+ end