0
|
1 |
#
|
|
2 |
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
3 |
# All rights reserved.
|
|
4 |
# This component and the accompanying materials are made available
|
|
5 |
# under the terms of "Eclipse Public License v1.0"
|
|
6 |
# which accompanies this distribution, and is available
|
|
7 |
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
|
8 |
#
|
|
9 |
# Initial Contributors:
|
|
10 |
# Nokia Corporation - initial contribution.
|
|
11 |
#
|
|
12 |
# Contributors:
|
|
13 |
#
|
|
14 |
# Description:
|
|
15 |
#
|
|
16 |
|
|
17 |
"""
|
|
18 |
|
|
19 |
"""
|
|
20 |
|
|
21 |
|
|
22 |
import getpass
|
|
23 |
import urllib, urllib2
|
|
24 |
import urlparse
|
|
25 |
from HTMLParser import HTMLParser
|
|
26 |
import sys
|
|
27 |
import os
|
|
28 |
import logging
|
|
29 |
import re
|
|
30 |
|
|
31 |
|
|
32 |
class SSOHTMLParser(HTMLParser):
|
|
33 |
"""
|
|
34 |
Simple html parser which understand what is needed to show the current
|
|
35 |
version of the SSO login page. End parsing at <\html>, which is in
|
|
36 |
current version of login page inside <noscript> before other stuff on page.
|
|
37 |
Asks form inputs of types text and password from the user.
|
|
38 |
The data is saved in varables inside class
|
|
39 |
"""
|
|
40 |
def __init__(self, *argv, **kwargs):
|
3
|
41 |
self.username_func = kwargs.pop('username_func',None)
|
|
42 |
self.password_func = kwargs.pop('password_func',None)
|
0
|
43 |
HTMLParser.__init__(self, *argv, **kwargs)
|
|
44 |
self.html_end = False
|
|
45 |
self.httpdata = {}
|
|
46 |
self.input_requested = False
|
|
47 |
self.input_entered = False
|
|
48 |
self.method = ''
|
|
49 |
self.action = ''
|
|
50 |
|
|
51 |
def handle_starttag(self, tag, attrs):
|
|
52 |
attrs = dict(attrs)
|
|
53 |
if self.html_end:
|
|
54 |
return
|
|
55 |
if tag == 'br':
|
|
56 |
print
|
|
57 |
elif tag == 'form':
|
|
58 |
self.action = attrs.get('action')
|
|
59 |
self.method = attrs.get('method')
|
|
60 |
elif tag == 'input':
|
|
61 |
inputtype = attrs.get('type', 'text')
|
|
62 |
if inputtype == 'hidden':
|
|
63 |
# Should the username be also overridable
|
|
64 |
self.httpdata[attrs.get('name')] = attrs.get('value')
|
|
65 |
if inputtype == 'password':
|
|
66 |
self.input_requested = True
|
3
|
67 |
data = self.password_func()
|
0
|
68 |
if data:
|
|
69 |
self.input_entered = True
|
|
70 |
self.httpdata[attrs.get('name')] = data
|
|
71 |
if inputtype == 'text':
|
|
72 |
self.input_requested = True
|
3
|
73 |
data = self.username_func()
|
0
|
74 |
if data:
|
|
75 |
self.input_entered = True
|
|
76 |
self.httpdata[attrs.get('name')] = data
|
|
77 |
if inputtype == 'submit':
|
|
78 |
self.httpdata['submit'] = attrs.get('value')
|
|
79 |
|
|
80 |
def handle_endtag(self, tag):
|
|
81 |
if self.html_end:
|
|
82 |
return
|
|
83 |
if tag == 'tr':
|
|
84 |
print
|
|
85 |
if tag == 'title':
|
|
86 |
print
|
|
87 |
if tag == 'html':
|
|
88 |
self.html_end = True
|
|
89 |
|
|
90 |
def handle_data(self, data):
|
|
91 |
if self.html_end:
|
|
92 |
return
|
|
93 |
if data.strip():
|
|
94 |
print data.strip(),
|
|
95 |
|
|
96 |
class CarbonAuthHandler(urllib2.AbstractHTTPHandler):
|
|
97 |
handler_order = 600
|
3
|
98 |
def __init__(self):
|
|
99 |
urllib2.AbstractHTTPHandler.__init__(self)
|
|
100 |
self.auth_count = 0
|
|
101 |
self.auth_max = 5
|
|
102 |
self.username = ""
|
|
103 |
self.password = ""
|
|
104 |
self.username_func = None
|
|
105 |
self.password_func = None
|
|
106 |
|
0
|
107 |
|
3
|
108 |
def add_username_func(self, username_func):
|
|
109 |
"""
|
|
110 |
Add password getting function
|
|
111 |
"""
|
|
112 |
self.username_func = username_func
|
|
113 |
|
|
114 |
def add_password_func(self, password_func):
|
|
115 |
"""
|
|
116 |
Add password getting function
|
0
|
117 |
"""
|
3
|
118 |
self.password_func = password_func
|
|
119 |
|
|
120 |
def get_username(self):
|
|
121 |
"""
|
|
122 |
Add password getting function
|
0
|
123 |
"""
|
3
|
124 |
if self.auth_count == 0 and self.username_func:
|
|
125 |
return self.username_func()
|
|
126 |
else:
|
|
127 |
self.username = raw_input("Username: ")
|
|
128 |
return self.username
|
|
129 |
|
|
130 |
def get_password(self):
|
|
131 |
"""
|
|
132 |
Add password getting function
|
|
133 |
"""
|
|
134 |
if self.auth_count == 0 and self.password_func:
|
|
135 |
return self.password_func()
|
|
136 |
else:
|
|
137 |
self.password = getpass.getpass()
|
|
138 |
return self.password
|
0
|
139 |
|
|
140 |
def https_response(self, request, response):
|
|
141 |
"""
|
|
142 |
Catches responses which are from sso login page and asks for the
|
|
143 |
information from the command line and posts it.
|
|
144 |
After posting urllib2 takes care of following redirects back to
|
|
145 |
original page.
|
|
146 |
"""
|
|
147 |
if (re.match('login.*\.europe\.nokia\.com', request.get_host())):
|
3
|
148 |
if self.auth_count > self.auth_max:
|
|
149 |
print "Authentication failed!"
|
|
150 |
return response
|
|
151 |
sso_parser = SSOHTMLParser(username_func=self.get_username, password_func=self.get_password)
|
0
|
152 |
sso_parser.feed(response.read())
|
3
|
153 |
self.auth_count += 1
|
|
154 |
|
0
|
155 |
# !sso_parser.input_requested when we have posted the form and
|
|
156 |
# are reading the redirect back. We don't want to handle that
|
|
157 |
if sso_parser.input_requested:
|
|
158 |
if not sso_parser.input_entered:
|
|
159 |
# By entering empty username and password you get
|
|
160 |
# out of infinite invalid login loop
|
|
161 |
# Only bad thing that the SSO login page doesen't
|
|
162 |
# tell you that login failed, only shows the same text
|
|
163 |
# again
|
|
164 |
raise urllib2.URLError("No login data entered")
|
|
165 |
newurl = urlparse.urljoin(request.get_full_url(), sso_parser.action)
|
|
166 |
ssoreq = urllib2.Request(newurl,
|
|
167 |
urllib.urlencode(sso_parser.httpdata),
|
|
168 |
origin_req_host=request.get_origin_req_host(),
|
|
169 |
unverifiable=True,
|
|
170 |
)
|
|
171 |
return self.parent.open(ssoreq)
|
|
172 |
return response
|
|
173 |
|
|
174 |
def http_response(self, request, response):
|
|
175 |
"""
|
|
176 |
Catches responses which are from normal carbon authenticatoin page and uses set password if found
|
|
177 |
or asks for the information from the command line and posts it.
|
|
178 |
After posting urllib2 takes care of following redirects back to
|
|
179 |
original page.
|
|
180 |
"""
|
|
181 |
if response.code == 200 and (re.match('.*/extauth/login/?.*', request.get_full_url())):
|
3
|
182 |
if self.auth_count > self.auth_max:
|
|
183 |
raise urllib2.HTTPError("Authentication failed!")
|
|
184 |
|
0
|
185 |
loginreq = urllib2.Request(request.get_full_url(),
|
3
|
186 |
urllib.urlencode({ 'username' : self.get_username(),
|
|
187 |
'password' : self.get_password(),
|
0
|
188 |
'submit' : 'login'}
|
|
189 |
),
|
|
190 |
origin_req_host=request.get_origin_req_host(),
|
|
191 |
unverifiable=True,
|
|
192 |
)
|
3
|
193 |
self.auth_count += 1
|
0
|
194 |
return self.parent.open(loginreq)
|
|
195 |
else:
|
|
196 |
return response
|