jan-leila / hubspace-py Goto Github PK
View Code? Open in Web Editor NEWLicense: MIT License
License: MIT License
Hey there,
It appears the location
field is missing from the https://accounts.hubspaceconnect.com/auth/realms/thd/login-actions/authenticate?session_code...
POST request response headers.
I'm guessing Hubspace (or Keycloak) changed their login flow & this needs to be re-reverse engineered?
Here's what I'm getting (after some basic logging & debugging):
\Python 3.9.2 (default, Mar 12 2021, 04:06:34)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from hubspace import Hubspace
>>> h = Hubspace('REDACTED', 'REDACTED')
>>> h.getAccountID()
code_challenge: a9z6xwiMzM669M2KXndaVRvC8LCqCv1H5WtQLh6xgwk
auth url: https://accounts.hubspaceconnect.com/auth/realms/thd/protocol/openid-connect/auth?response_type=code&client_id=hubspace_android&redirect_uri=hubspace-app%3A%2F%2Floginredirect&code_challenge=a9z6xwiMzM669M2KXndaVRvC8LCqCv1H5WtQLh6xgwk&code_challenge_method=S256&scope=openid+offline_access
auth headers: {'User-Agent': 'python-requests/2.27.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
auth response: 200 - <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" class="login-pf">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="robots" content="noindex, nofollow">
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css">
<link rel="icon" href="#" />
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>Log in to Hubspace</title>
<link href="/auth/resources/zpbf1/common/keycloak/web_modules/@patternfly/react-core/dist/styles/base.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/common/keycloak/web_modules/@patternfly/react-core/dist/styles/app.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/common/keycloak/node_modules/patternfly/dist/css/patternfly.min.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/common/keycloak/node_modules/patternfly/dist/css/patternfly-additions.min.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/common/keycloak/lib/pficon/pficon.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/login/hubspace/css/login.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/login/hubspace/css/style.css" rel="stylesheet" />
<script type="text/javascript">
function getUrlVars() {
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
function togglePassword(id) {
var passwordField = document.getElementById(id);
var passwordFieldToggle = document.getElementById('bt-toggle-' + id);
if(passwordField.getAttribute('type') === 'password') {
passwordField.setAttribute('type', 'text');
passwordFieldToggle.value = 'Hide';
} else {
passwordField.setAttribute('type', 'password');
passwordFieldToggle.value = 'Show';
}
}
function clickLocale() {
var localeDropdown = document.querySelector("#kc-locale ul");
localeDropdown.style.display = localeDropdown.style.display != "block" ? "block" : "none";
}
document.addEventListener("DOMContentLoaded", function(event) {
var usernameField = document.getElementById('username');
var usernameInput = getUrlVars()['username'];
if (usernameInput) {
usernameField.value = decodeURIComponent(usernameInput);
}
var acceptChk = document.getElementById('acceptterms');
if (acceptChk) {
acceptChk.onclick = function () {
var login = document.getElementById('login-button');
console.log('Disabled ' + login.disabled);
if(acceptChk.checked) {
console.log('enable');
login.disabled = false;
} else {
console.log('disable');
login.disabled = true;
}
}
}
}
);
</script>
</head>
<body class="">
<div class="login-pf-page">
<div id="kc-header" class="login-pf-page-header">
<img src="/auth/resources/zpbf1/login/hubspace/img/hubspace-mobile-logo.png" alt="Hubspace logo" width="628" height="106">
</div>
<div class="card-pf ">
<header class="login-pf-header">
<div id="kc-locale">
<div id="kc-locale-wrapper" class="">
<div class="kc-dropdown" id="kc-locale-dropdown">
<button id="kc-current-locale-link" type="button" onClick="clickLocale()" tabindex=0>
English
</button>
<ul>
<li class="kc-dropdown-item"><a href="/auth/realms/thd/login-actions/authenticate?client_id=hubspace_android&tab_id=JwcAo1y86cw&execution=3d17da1d-df31-42cd-8aa1-a3555b457e26&kc_locale=en">English</a></li>
<li class="kc-dropdown-item"><a href="/auth/realms/thd/login-actions/authenticate?client_id=hubspace_android&tab_id=JwcAo1y86cw&execution=3d17da1d-df31-42cd-8aa1-a3555b457e26&kc_locale=fr">Fran�?ais</a></li>
<li class="kc-dropdown-item"><a href="/auth/realms/thd/login-actions/authenticate?client_id=hubspace_android&tab_id=JwcAo1y86cw&execution=3d17da1d-df31-42cd-8aa1-a3555b457e26&kc_locale=es">Espa�?ol</a></li>
</ul>
</div>
</div>
</div>
<h1 id="kc-page-title"> Sign In
</h1>
</header>
<div id="kc-content">
<div id="kc-content-wrapper">
<div id="kc-form" >
<div id="kc-form-wrapper" >
<form id="kc-form-login" onsubmit="login.disabled = true; return true;" action="https://accounts.hubspaceconnect.com/auth/realms/thd/login-actions/authenticate?session_code=v9WVbf4WfAEEkUfVEYOzDgYqNJMxAjJVubnT2Fqw_LQ&execution=3d17da1d-df31-42cd-8aa1-a3555b457e26&client_id=hubspace_android&tab_id=JwcAo1y86cw" method="post">
<div class="form-group">
<label for="username" class="form-label">Email</label>
<input tabindex="0" id="username" class="form-control" name="username" value="" type="text" inputmode="email" autofocus autocomplete="off" />
</div>
<div class="form-group">
<label for="password" class="form-label">Password</label>
<input tabindex="0" id="password" class="form-control" name="password" type="password" autocomplete="off"/>
<input type="button" class="bt-password-toggle" id="bt-toggle-password" onClick="togglePassword('password')" value='Show'/>
</div>
<div class="form-group login-pf-settings">
<div id="kc-form-options">
</div>
</div>
<div id="kc-form-buttons" class="form-group">
<input type="hidden" id="id-hidden-input" name="credentialId" />
<input tabindex="0" class="pf-c-button pf-m-primary btn-block btn-lg" name="login" id="kc-login" type="submit" value="Sign In"/>
</div>
<div id="kc-form-buttons" class="form-group">
<a tabindex="0" href="/auth/realms/thd/login-actions/registration?client_id=hubspace_android&tab_id=JwcAo1y86cw" class="btn reg-button">Register</a>
</div>
</form>
</div>
</div>
<div id="kc-info" class="login-pf-signup">
<div id="kc-info-wrapper" class="">
<span><a tabindex="0" href="/auth/realms/thd/login-actions/reset-credentials?client_id=hubspace_android&tab_id=JwcAo1y86cw">Forgot Password?</a></span>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
- {'cache-control': 'no-store, must-revalidate, max-age=0', 'set-cookie': 'AUTH_SESSION_ID=f96ec3fb-2e14-4422-a490-7d4476295aff.keycloak-2; Version=1; Path=/auth/realms/thd/; SameSite=None; Secure; HttpOnly, AUTH_SESSION_ID_LEGACY=f96ec3fb-2e14-4422-a490-7d4476295aff.keycloak-2; Version=1; Path=/auth/realms/thd/; Secure; HttpOnly, KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2OThhMDY0NS0wZDljLTRlYTktODhiZS0xYzc1OGVjOGIxOGYifQ.eyJjaWQiOiJodWJzcGFjZV9hbmRyb2lkIiwicHR5Ijoib3BlbmlkLWNvbm5lY3QiLCJydXJpIjoiaHVic3BhY2UtYXBwOi8vbG9naW5yZWRpcmVjdCIsImFjdCI6IkFVVEhFTlRJQ0FURSIsIm5vdGVzIjp7InNjb3BlIjoib3BlbmlkIG9mZmxpbmVfYWNjZXNzIiwiaXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5odWJzcGFjZWNvbm5lY3QuY29tL2F1dGgvcmVhbG1zL3RoZCIsInJlc3BvbnNlX3R5cGUiOiJjb2RlIiwiY29kZV9jaGFsbGVuZ2VfbWV0aG9kIjoiUzI1NiIsInJlZGlyZWN0X3VyaSI6Imh1YnNwYWNlLWFwcDovL2xvZ2lucmVkaXJlY3QiLCJjb2RlX2NoYWxsZW5nZSI6ImE5ejZ4d2lNek02NjlNMktYbmRhVlJ2QzhMQ3FDdjFINVd0UUxoNnhnd2sifX0.mHeidkIaJqs3hdMeHGxZOcDEAGmxFPQLnXIdCal1o-4; Version=1; Path=/auth/realms/thd/; Secure; HttpOnly', 'x-xss-protection': '1; mode=block', 'x-frame-options': 'SAMEORIGIN', 'referrer-policy': 'no-referrer', 'content-security-policy': "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 'date': 'Wed, 10 May 2023 03:08:04 GMT', 'x-robots-tag': 'none', 'strict-transport-security': 'max-age=31536000; includeSubDomains', 'x-content-type-options': 'nosniff', 'content-type': 'text/html;charset=utf-8', 'content-length': '7719', 'content-language': 'en'}
session url: https://accounts.hubspaceconnect.com/auth/realms/thd/login-actions/authenticate?session_code=v9WVbf4WfAEEkUfVEYOzDgYqNJMxAjJVubnT2Fqw_LQ&execution=3d17da1d-df31-42cd-8aa1-a3555b457e26&client_id=hubspace_android&tab_id=JwcAo1y86cw
session body: username=REDACTED&password=REDACTED&credentialId=
session headers: {'User-Agent': 'python-requests/2.27.1', 'accept-encoding': 'gzip', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded', 'Cookie': 'AUTH_SESSION_ID=f96ec3fb-2e14-4422-a490-7d4476295aff.keycloak-2; AUTH_SESSION_ID_LEGACY=f96ec3fb-2e14-4422-a490-7d4476295aff.keycloak-2; KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2OThhMDY0NS0wZDljLTRlYTktODhiZS0xYzc1OGVjOGIxOGYifQ.eyJjaWQiOiJodWJzcGFjZV9hbmRyb2lkIiwicHR5Ijoib3BlbmlkLWNvbm5lY3QiLCJydXJpIjoiaHVic3BhY2UtYXBwOi8vbG9naW5yZWRpcmVjdCIsImFjdCI6IkFVVEhFTlRJQ0FURSIsIm5vdGVzIjp7InNjb3BlIjoib3BlbmlkIG9mZmxpbmVfYWNjZXNzIiwiaXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5odWJzcGFjZWNvbm5lY3QuY29tL2F1dGgvcmVhbG1zL3RoZCIsInJlc3BvbnNlX3R5cGUiOiJjb2RlIiwiY29kZV9jaGFsbGVuZ2VfbWV0aG9kIjoiUzI1NiIsInJlZGlyZWN0X3VyaSI6Imh1YnNwYWNlLWFwcDovL2xvZ2lucmVkaXJlY3QiLCJjb2RlX2NoYWxsZW5nZSI6ImE5ejZ4d2lNek02NjlNMktYbmRhVlJ2QzhMQ3FDdjFINVd0UUxoNnhnd2sifX0.mHeidkIaJqs3hdMeHGxZOcDEAGmxFPQLnXIdCal1o-4', 'Content-Length': '67'}
session response: 200 - <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" class="login-pf">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="robots" content="noindex, nofollow">
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css">
<link rel="icon" href="#" />
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>Log in to Hubspace</title>
<link href="/auth/resources/zpbf1/common/keycloak/web_modules/@patternfly/react-core/dist/styles/base.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/common/keycloak/web_modules/@patternfly/react-core/dist/styles/app.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/common/keycloak/node_modules/patternfly/dist/css/patternfly.min.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/common/keycloak/node_modules/patternfly/dist/css/patternfly-additions.min.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/common/keycloak/lib/pficon/pficon.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/login/hubspace/css/login.css" rel="stylesheet" />
<link href="/auth/resources/zpbf1/login/hubspace/css/style.css" rel="stylesheet" />
<script type="text/javascript">
function getUrlVars() {
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
function togglePassword(id) {
var passwordField = document.getElementById(id);
var passwordFieldToggle = document.getElementById('bt-toggle-' + id);
if(passwordField.getAttribute('type') === 'password') {
passwordField.setAttribute('type', 'text');
passwordFieldToggle.value = 'Hide';
} else {
passwordField.setAttribute('type', 'password');
passwordFieldToggle.value = 'Show';
}
}
function clickLocale() {
var localeDropdown = document.querySelector("#kc-locale ul");
localeDropdown.style.display = localeDropdown.style.display != "block" ? "block" : "none";
}
document.addEventListener("DOMContentLoaded", function(event) {
var usernameField = document.getElementById('username');
var usernameInput = getUrlVars()['username'];
if (usernameInput) {
usernameField.value = decodeURIComponent(usernameInput);
}
var acceptChk = document.getElementById('acceptterms');
if (acceptChk) {
acceptChk.onclick = function () {
var login = document.getElementById('login-button');
console.log('Disabled ' + login.disabled);
if(acceptChk.checked) {
console.log('enable');
login.disabled = false;
} else {
console.log('disable');
login.disabled = true;
}
}
}
}
);
</script>
<SCRIPT> if (typeof history.replaceState === 'function') { history.replaceState({}, "some title", "https://accounts.hubspaceconnect.com/auth/realms/thd/login-actions/authenticate?execution=3d17da1d-df31-42cd-8aa1-a3555b457e26&client_id=hubspace_android&tab_id=JwcAo1y86cw"); }</SCRIPT></head>
<body class="">
<div class="login-pf-page">
<div id="kc-header" class="login-pf-page-header">
<img src="/auth/resources/zpbf1/login/hubspace/img/hubspace-mobile-logo.png" alt="Hubspace logo" width="628" height="106">
</div>
<div class="card-pf ">
<header class="login-pf-header">
<div id="kc-locale">
<div id="kc-locale-wrapper" class="">
<div class="kc-dropdown" id="kc-locale-dropdown">
<button id="kc-current-locale-link" type="button" onClick="clickLocale()" tabindex=0>
English
</button>
<ul>
<li class="kc-dropdown-item"><a href="/auth/realms/thd/login-actions/authenticate?client_id=hubspace_android&tab_id=JwcAo1y86cw&execution=3d17da1d-df31-42cd-8aa1-a3555b457e26&kc_locale=en">English</a></li>
<li class="kc-dropdown-item"><a href="/auth/realms/thd/login-actions/authenticate?client_id=hubspace_android&tab_id=JwcAo1y86cw&execution=3d17da1d-df31-42cd-8aa1-a3555b457e26&kc_locale=fr">Fran�?ais</a></li>
<li class="kc-dropdown-item"><a href="/auth/realms/thd/login-actions/authenticate?client_id=hubspace_android&tab_id=JwcAo1y86cw&execution=3d17da1d-df31-42cd-8aa1-a3555b457e26&kc_locale=es">Espa�?ol</a></li>
</ul>
</div>
</div>
</div>
<h1 id="kc-page-title"> Sign In
</h1>
</header>
<div id="kc-content">
<div id="kc-content-wrapper">
<div class="alert alert-error">
<span class="fa fa-fw fa-exclamation-circle"></span>
<span class="kc-feedback-text">Invalid username or password.</span>
</div>
<div id="kc-form" >
<div id="kc-form-wrapper" >
<form id="kc-form-login" onsubmit="login.disabled = true; return true;" action="https://accounts.hubspaceconnect.com/auth/realms/thd/login-actions/authenticate?session_code=_666OIZbuqJZGLNwZQokFhMAsVK6PTPdvJQ-elYcR1s&execution=3d17da1d-df31-42cd-8aa1-a3555b457e26&client_id=hubspace_android&tab_id=JwcAo1y86cw" method="post">
<div class="form-group">
<label for="username" class="form-label">Email</label>
<input tabindex="0" id="username" class="form-control" name="username" value="REDACTED" type="text" inputmode="email" autofocus autocomplete="off" />
</div>
<div class="form-group">
<label for="password" class="form-label">Password</label>
<input tabindex="0" id="password" class="form-control" name="password" type="password" autocomplete="off"/>
<input type="button" class="bt-password-toggle" id="bt-toggle-password" onClick="togglePassword('password')" value='Show'/>
</div>
<div class="form-group login-pf-settings">
<div id="kc-form-options">
</div>
</div>
<div id="kc-form-buttons" class="form-group">
<input type="hidden" id="id-hidden-input" name="credentialId" />
<input tabindex="0" class="pf-c-button pf-m-primary btn-block btn-lg" name="login" id="kc-login" type="submit" value="Sign In"/>
</div>
<div id="kc-form-buttons" class="form-group">
<a tabindex="0" href="/auth/realms/thd/login-actions/registration?client_id=hubspace_android&tab_id=JwcAo1y86cw" class="btn reg-button">Register</a>
</div>
</form>
</div>
</div>
<div id="kc-info" class="login-pf-signup">
<div id="kc-info-wrapper" class="">
<span><a tabindex="0" href="/auth/realms/thd/login-actions/reset-credentials?client_id=hubspace_android&tab_id=JwcAo1y86cw">Forgot Password?</a></span>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
- {'cache-control': 'no-store, must-revalidate, max-age=0', 'x-xss-protection': '1; mode=block', 'x-frame-options': 'SAMEORIGIN', 'referrer-policy': 'no-referrer', 'content-security-policy': "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 'date': 'Wed, 10 May 2023 03:08:05 GMT', 'x-robots-tag': 'none', 'strict-transport-security': 'max-age=31536000; includeSubDomains', 'x-content-type-options': 'nosniff', 'content-type': 'text/html;charset=utf-8', 'content-length': '8302', 'content-language': 'en'}
None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/pi/.local/lib/python3.9/site-packages/hubspace/hubspace.py", line 13, in getAccountID
return self._user.getAccountID()
File "/home/pi/.local/lib/python3.9/site-packages/hubspace/hubspace_user.py", line 187, in getAccountID
self._accountID = self.getInfo()['accountAccess'][0]['account']['accountId']
File "/home/pi/.local/lib/python3.9/site-packages/hubspace/hubspace_user.py", line 183, in getInfo
return self.get("users/me")
File "/home/pi/.local/lib/python3.9/site-packages/hubspace/hubspace_user.py", line 161, in get
headers=self._getHeaders(host),
File "/home/pi/.local/lib/python3.9/site-packages/hubspace/hubspace_user.py", line 150, in _getHeaders
"authorization": self._getAuthorization(),
File "/home/pi/.local/lib/python3.9/site-packages/hubspace/hubspace_user.py", line 130, in _getAuthorization
return "Bearer " + self._getAccessToken()
File "/home/pi/.local/lib/python3.9/site-packages/hubspace/hubspace_user.py", line 112, in _getAccessToken
"refresh_token": self._getRefreshToken(),
File "/home/pi/.local/lib/python3.9/site-packages/hubspace/hubspace_user.py", line 98, in _getRefreshToken
self._refresh_token = _getRefreshToken(self._username, self._password)
File "/home/pi/.local/lib/python3.9/site-packages/hubspace/hubspace_user.py", line 60, in _getRefreshToken
code = re.search(b'&code=(.+?)$', location).group(1)
File "/usr/lib/python3.9/re.py", line 201, in search
return _compile(pattern, flags).search(string)
TypeError: expected string or bytes-like object
>>>
p.s. Great work! I hope you can keep this maintained (or even make it official).
One other small request would be to use the python logging
module to make debugging changes like this easier in the future (and so that all issues have a standard format to them).
Thanks again for your efforts on this :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.