9 This class wraps one instance of Untangle. It gets initialized with
10 some configuration information, and then provides the methods to
13 def __init__(self
, s
):
15 Initialize this Untangle object with a ConfigParser section.
19 self
.username
= s
.get('username', 'admin')
20 self
.password
= s
['password']
21 self
.timeout
= s
.get('timeout', 300)
22 self
.base_url
= 'https://' + self
.host
+ '/' # This never changes
24 # Sanity check the numerical version.
25 self
.version
= s
.get('version', '14.1')
26 if self
.version
not in ['9', '10', '11', '12', '13', '13.1',
28 msg
= 'Invalid version "' + self
.version
+ '" '
29 msg
+= 'in section "' + s
.name
+ '"'
30 raise configparser
.ParsingError(msg
)
32 # Sanity check the boolean verify_cert parameter.
33 vc
= s
.get('verify_cert', 'False')
35 self
.verify_cert
= True
37 self
.verify_cert
= False
39 msg
= 'Invalid value "' + vc
+ '" for verify_cert '
40 msg
+= 'in section "' + s
.name
+ '"'
41 raise configparser
.ParsingError(msg
)
43 # Sanity check the integer "timeout" parameter. We want to
44 # bail if either the given parameter is not an integer, or if
45 # it's negative. To handle both at the same time, we try to
47 timeout
= s
.get('timeout', 300)
49 self
.timeout
= int(timeout
)
51 # ...and set self.timeout to a negative value if we can't...
54 # Now we check to see if the timeout value is negative. That
55 # will happen if it was either negative to begin with, or
56 # non-integer (and we set it negative).
58 msg
= 'Invalid value "' + timeout
+ '" for timeout '
59 msg
+= 'in section "' + s
.name
+ '"'
60 raise configparser
.ParsingError(msg
)
62 # Finally, create a URL opener to make HTTPS requests.
64 # First, create a cookie jar that we'll attach to our URL
66 cj
= http
.cookiejar
.CookieJar()
67 cookie_proc
= urllib
.request
.HTTPCookieProcessor(cj
)
69 # SSL mumbo jumbo to make it ignore the certificate's hostname
70 # when verify_cert = False.
71 ssl_ctx
= ssl
.create_default_context()
72 if not self
.verify_cert
:
73 ssl_ctx
.check_hostname
= False
74 ssl_ctx
.verify_mode
= ssl
.CERT_NONE
76 https_handler
= urllib
.request
.HTTPSHandler(context
=ssl_ctx
)
78 # Now Create a URL opener, and tell it to use our cookie jar
79 # and SSL context. We keep this around for future requests.
80 self
.opener
= urllib
.request
.build_opener(https_handler
, cookie_proc
)
83 def open(self
, url
, data
=None):
85 A wrapper around ``self.opener.open()`` that uses our
86 configurable socket "timeout" value. Without the timeout
87 parameter, it seems we can wait forever in some corner cases.
89 return self
.opener
.open(url
, data
, self
.timeout
)
94 Perform the HTTPS request to log in to the Untangle web admin
95 UI. The resulting session cookie is stored by our ``self.opener``.
97 login_path
= 'auth/login?url=/setup/welcome.do&realm=Administrator'
98 url
= self
.base_url
+ login_path
99 post_vars
= {'username': self.username, 'password': self.password }
100 post_data
= urllib
.parse
.urlencode(post_vars
).encode('ascii')
101 self
.open(url
, post_data
)
104 def get_backup(self
):
106 Version-agnostic get-me-a-backup method. Dispatches to the
107 actual implementation based on ``self.version``.
109 if self
.version
== '9':
110 return self
.get_backup_v9()
111 elif self
.version
in ['10', '11', '12', '13']:
112 # The procedure for v11, v12, or v13 is the same as for v10.
113 return self
.get_backup_v10()
114 elif self
.version
in ['13.1', '14', '14.1']:
115 # But the minor update v13.1 moved the backup URL.
116 return self
.get_backup_v13_1()
118 raise ValueError('unknown version %s' % self
.version
)
121 def get_backup_v9(self
):
123 Retrieve a backup from Untangle version 9. This requires two
124 requests; the first just hits the page, and the second actually
125 retrieves the backup file.
127 Returns the binary HTTPS response (i.e. the file).
129 url
= self
.base_url
+ '/webui/backup'
130 post_vars
= {'action': 'requestBackup'}
131 post_data
= urllib
.parse
.urlencode(post_vars
).encode('ascii')
132 self
.open(url
, post_data
)
134 url
= self
.base_url
+ 'webui/backup?action=initiateDownload'
135 with self
.open(url
) as response
:
136 return response
.read()
139 def get_backup_v10(self
):
141 Retrieve a backup from Untangle version 10.
143 Returns the binary HTTPS response (i.e. the file).
145 url
= self
.base_url
+ '/webui/download'
146 post_vars
= {'type': 'backup'}
147 post_data
= urllib
.parse
.urlencode(post_vars
).encode('ascii')
148 with self
.open(url
, post_data
) as response
:
149 return response
.read()
152 def get_backup_v13_1(self
):
154 Retrieve a backup from Untangle version 13.1. This
155 differs from v13 (and v12, and v11,...) by only one word
156 in the URL: "webui" becomes "admin".
158 Returns the binary HTTPS response (i.e. the file).
160 url
= self
.base_url
+ '/admin/download'
161 post_vars
= {'type': 'backup'}
162 post_data
= urllib
.parse
.urlencode(post_vars
).encode('ascii')
163 with self
.open(url
, post_data
) as response
:
164 return response
.read()