aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-extended/python-pykickstart/files/0001-support-authentication-for-kickstart.patch
blob: 6af4bde08af7932726680c8659b4f82aa98f2357 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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
140
141
142
143
144
145
146
147
148
From b7070a79432b790dffa82401364e4fd8d906eb2b Mon Sep 17 00:00:00 2001
From: Hongxu Jia <hongxu.jia@windriver.com>
Date: Tue, 31 Jul 2018 17:24:47 +0800
Subject: [PATCH 1/4] support authentication for kickstart

While download kickstart file from web server,
we support basic/digest authentication.

Add KickstartAuthError to report authentication failure,
which the invoker could parse this specific error.

Upstream-Status: inappropriate [oe specific]

Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
---
 pykickstart/errors.py | 17 +++++++++++++++++
 pykickstart/load.py   | 34 ++++++++++++++++++++++++++++------
 pykickstart/parser.py |  4 ++--
 3 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/pykickstart/errors.py b/pykickstart/errors.py
index bf08ac5..aada7aa 100644
--- a/pykickstart/errors.py
+++ b/pykickstart/errors.py
@@ -32,6 +32,9 @@ This module exports several exception classes:
     KickstartVersionError - An exception for errors relating to unsupported
                             syntax versions.
 
+    KickstartAuthError - An exception for errors relating to authentication
+                         failed while downloading kickstart from web server
+
 And some warning classes:
 
     KickstartWarning - A generic warning class.
@@ -131,3 +134,17 @@ class KickstartDeprecationWarning(KickstartParseWarning, DeprecationWarning):
        commands and options.
     """
     pass
+
+class KickstartAuthError(KickstartError):
+    """An exception for errors relating to authentication failed while
+       downloading kickstart from web server
+    """
+    def __init__(self, msg):
+        """Create a new KickstartAuthError exception instance with the
+           descriptive message val.  val should be the return value of
+           formatErrorMsg.
+        """
+        KickstartError.__init__(self, msg)
+
+    def __str__(self):
+        return self.value
diff --git a/pykickstart/load.py b/pykickstart/load.py
index fb935f2..c6f013f 100644
--- a/pykickstart/load.py
+++ b/pykickstart/load.py
@@ -18,10 +18,13 @@
 # with the express permission of Red Hat, Inc.
 #
 import requests
+from requests.auth import HTTPDigestAuth
+from requests.auth import HTTPBasicAuth
+
 import shutil
 import six
 
-from pykickstart.errors import KickstartError
+from pykickstart.errors import KickstartError, KickstartAuthError
 from pykickstart.i18n import _
 from requests.exceptions import SSLError, RequestException
 
@@ -29,7 +32,7 @@ _is_url = lambda location: '://' in location  # RFC 3986
 
 SSL_VERIFY = True
 
-def load_to_str(location):
+def load_to_str(location, user=None, passwd=None):
     '''Load a destination URL or file into a string.
     Type of input is inferred automatically.
 
@@ -40,7 +43,7 @@ def load_to_str(location):
     Raises: KickstartError on error reading'''
 
     if _is_url(location):
-        return _load_url(location)
+        return _load_url(location, user=user, passwd=passwd)
     else:
         return _load_file(location)
 
@@ -70,11 +73,30 @@ def load_to_file(location, destination):
         _copy_file(location, destination)
         return destination
 
-def _load_url(location):
-    '''Load a location (URL or filename) and return contents as string'''
+def _get_auth(location, user=None, passwd=None):
+
+    auth = None
+    request = requests.get(location, verify=SSL_VERIFY)
+    if request.status_code == requests.codes.unauthorized:
+        if user is None or passwd is None:
+            log.info("Require Authentication")
+            raise KickstartAuthError("Require Authentication.\nAppend 'ksuser=<username> kspasswd=<password>' to boot command")
+
+        reasons = request.headers.get("WWW-Authenticate", "").split()
+        if reasons:
+            auth_type = reasons[0]
+        if auth_type == "Basic":
+            auth = HTTPBasicAuth(user, passwd)
+        elif auth_type == "Digest":
+            auth=HTTPDigestAuth(user, passwd)
+
+    return auth
 
+def _load_url(location, user=None, passwd=None):
+     '''Load a location (URL or filename) and return contents as string'''
+    auth = _get_auth(location, user=user, passwd=passwd)
     try:
-        request = requests.get(location, verify=SSL_VERIFY)
+        request = requests.get(location, verify=SSL_VERIFY, auth=auth)
     except SSLError as e:
         raise KickstartError(_('Error securely accessing URL "%s"') % location + ': {e}'.format(e=str(e)))
     except RequestException as e:
diff --git a/pykickstart/parser.py b/pykickstart/parser.py
index d8880eb..22d14cb 100644
--- a/pykickstart/parser.py
+++ b/pykickstart/parser.py
@@ -787,7 +787,7 @@ class KickstartParser(object):
         i = PutBackIterator(s.splitlines(True) + [""])
         self._stateMachine(i)
 
-    def readKickstart(self, f, reset=True):
+    def readKickstart(self, f, reset=True, username=None, password=None):
         """Process a kickstart file, given by the filename f."""
         if reset:
             self._reset()
@@ -808,7 +808,7 @@ class KickstartParser(object):
         self.currentdir[self._includeDepth] = cd
 
         try:
-            s = load_to_str(f)
+            s = load_to_str(f, user=username, passwd=password)
         except KickstartError as e:
             raise KickstartError(_("Unable to open input kickstart file: %s") % str(e), lineno=0)
 
-- 
2.7.4