def get_user_info_after_auth(request): flow = get_flow(request.session['reddit-redirect-url']) del request.session['reddit-redirect-url'] state = request.session['reddit-state'] del request.session['reddit-state'] # Verify that the state matches if str(request.GET['state']) != str(state): raise FlowExchangeError('State does not match! Expected %s got %s' % (state, request.GET['state'])) code = request.GET['code'] credentials = step2_exchange(flow, code) # Needs to be modified for reddit OAuth # get the nice name http = httplib2.Http(".cache") http = credentials.authorize(http) (resp_headers, content) = http.request("https://oauth.reddit.com/api/v1/me", "GET") response = json.loads(content) name = response['name'] return { 'type': 'reddit', 'user_id': name, 'name': name, 'info': { 'name': name }, 'token': {} }
async def test_expired_after_exchange( hass: HomeAssistant, mock_code_flow: Mock, component_setup: ComponentSetup, ) -> None: """Test credential exchange expires.""" assert await component_setup() result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_USER}) assert result.get("type") == "progress" assert result.get("step_id") == "auth" assert "description_placeholders" in result assert "url" in result["description_placeholders"] # Fail first attempt then advance clock past exchange timeout with patch( "homeassistant.components.google.api.OAuth2WebServerFlow.step2_exchange", side_effect=FlowExchangeError(), ): now = utcnow() await fire_alarm(hass, now + datetime.timedelta(seconds=65)) await hass.async_block_till_done() result = await hass.config_entries.flow.async_configure( flow_id=result["flow_id"]) assert result.get("type") == "abort" assert result.get("reason") == "code_expired"
def exchange(self, code=None, redirect_uri=None): if code and redirect_uri != None: self.auth = [{'code': code, 'redirect_uri': redirect_uri}] + self.auth error = '' if len(self.auth) == 0: raise FlowExchangeError("Can't exchange without auth code") for auth in self.auth: body = urllib.urlencode({ 'grant_type': 'authorization_code', 'client_id': self.client_id, 'client_secret': self.client_secret, 'code': auth['code'], 'redirect_uri': auth['redirect_uri'], 'scope': self.scope }) headers = { 'content-type': 'application/x-www-form-urlencoded', } http = httplib2.Http(timeout=0.5) logger.info("Exchanging code {code} for new token".format(**auth)) try: resp, content = http.request(self.token_uri, method='POST', body=body, headers=headers) logger.info("Token exchange response: %s", content) if resp.status == 200: d = dict([el.split('=') for el in content.split('&')]) access_token = d['access_token'] refresh_token = d.get('refresh_token', None) token_expiry = None if 'expires' in d: token_expiry = datetime.datetime.utcnow() + datetime.timedelta( seconds=int(d['expires'])) self._credentials = OAuth2Credentials(access_token, self.client_id, self.client_secret, refresh_token, token_expiry, self.token_uri, self.user_agent, id_token=d.get('id_token', None)) return self._credentials else: error = error + str(content) + "\n" except SSLError as e: logger.warn("SSLError occurred exchanging facebook code for token") error = error + "SSLError: " + e.message + "\n" else: raise FlowExchangeError(error)
def test_reply_server_fail(self): msg = 'Whut!' self.OAuth2WebServerFlow( ).step2_exchange.side_effect = FlowExchangeError(msg) return self._test_command( 'oauth somebiglongoauthreturncode', 'Sorry {0} "{1}" happened. Try "!v1 oauth" again from the start'. format(self.nick, msg), to_nick=True, )
def test_run_flow_no_webserver_exchange_error(self, input_mock, logging_mock): input_mock.return_value = 'auth_code' self.flow.step2_exchange.side_effect = FlowExchangeError() # Error while exchanging. with self.assertRaises(SystemExit): tools.run_flow(self.flow, self.storage, flags=self.flags) self.flow.step2_exchange.assert_called_once_with('auth_code', http=None)
async def test_exchange_error( hass: HomeAssistant, mock_code_flow: Mock, component_setup: ComponentSetup, mock_notification: Mock, ) -> None: """Test an error while exchanging the code for credentials.""" with patch( "oauth2client.client.OAuth2WebServerFlow.step2_exchange", side_effect=FlowExchangeError(), ): assert await component_setup() now = utcnow() await fire_alarm(hass, now + CODE_CHECK_ALARM_TIMEDELTA) assert not hass.states.get("calendar.backyard_light") mock_notification.assert_called() assert "In order to authorize Home-Assistant" in mock_notification.call_args[ 0][1]
async def test_exchange_error( hass: HomeAssistant, mock_code_flow: Mock, mock_exchange: Mock, component_setup: ComponentSetup, ) -> None: """Test an error while exchanging the code for credentials.""" assert await component_setup() result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_USER}) assert result.get("type") == "progress" assert result.get("step_id") == "auth" assert "description_placeholders" in result assert "url" in result["description_placeholders"] # Run one tick to invoke the credential exchange check now = utcnow() with patch( "oauth2client.client.OAuth2WebServerFlow.step2_exchange", side_effect=FlowExchangeError(), ): now += CODE_CHECK_ALARM_TIMEDELTA await fire_alarm(hass, now) await hass.async_block_till_done() # Status has not updated, will retry result = await hass.config_entries.flow.async_configure( flow_id=result["flow_id"]) assert result.get("type") == "progress" assert result.get("step_id") == "auth" # Run another tick, which attempts credential exchange again with patch("homeassistant.components.google.async_setup_entry", return_value=True) as mock_setup: now += CODE_CHECK_ALARM_TIMEDELTA await fire_alarm(hass, now) await hass.async_block_till_done() result = await hass.config_entries.flow.async_configure( flow_id=result["flow_id"]) assert result.get("type") == "create_entry" assert result.get("title") == "Configuration.yaml" assert "data" in result data = result["data"] assert "token" in data data["token"].pop("expires_at") data["token"].pop("expires_in") assert data == { "auth_implementation": "device_auth", "token": { "access_token": "ACCESS_TOKEN", "refresh_token": "REFRESH_TOKEN", "scope": "https://www.googleapis.com/auth/calendar", "token_type": "Bearer", }, } assert len(mock_setup.mock_calls) == 1 entries = hass.config_entries.async_entries(DOMAIN) assert len(entries) == 1
def test_get_credentials_failure(self, authenticator): from ..authenticator import AuthenticationError authenticator.flow = flow = mock.Mock(name='flow') flow.step2_exchange.side_effect = FlowExchangeError('testing') with pytest.raises(AuthenticationError): authenticator._get_credentials('CODE')
def local_throws(code): raise FlowExchangeError("test")
def must_crach_flow_exception_and_reraise(self, credentials_from_code): credentials_from_code.return_value = mock.MagicMock(access_token='bar') credentials_from_code.side_effect = FlowExchangeError('some_error') with pytest.raises(google.GoogleOAuth2Exception): google.get_credentials('foo', '')
def step2_exchange(self, code, http=None): """ Don't send scope in step2 """ if not (isinstance(code, str) or isinstance(code, unicode)): if 'code' not in code: if 'error' in code: error_msg = code['error'] else: error_msg = 'No code was supplied in the query parameters.' raise FlowExchangeError(error_msg) else: code = code['code'] body = urllib.urlencode({ 'grant_type': 'authorization_code', 'client_id': self.client_id, 'client_secret': self.client_secret, 'code': code, 'redirect_uri': self.redirect_uri, }) headers = { 'content-type': 'application/x-www-form-urlencoded', } if self.user_agent is not None: headers['user-agent'] = self.user_agent if http is None: http = httplib2.Http() resp, content = http.request(self.token_uri, method='POST', body=body, headers=headers) d = _parse_exchange_token_response(content) if resp.status == 200 and 'access_token' in d: access_token = d['access_token'] refresh_token = d.get('refresh_token', None) token_expiry = None if 'expires_in' in d: token_expiry = datetime.datetime.utcnow() + datetime.timedelta( seconds=int(d['expires_in'])) if 'id_token' in d: d['id_token'] = _extract_id_token(d['id_token']) logger.info('Successfully retrieved access token') return OAuth2Credentials(access_token, self.client_id, self.client_secret, refresh_token, token_expiry, self.token_uri, self.user_agent, id_token=d.get('id_token', None)) else: logger.info('Failed to retrieve access token: %s' % content) if 'error' in d: # you never know what those providers got to say error_msg = unicode(d['error']) else: error_msg = 'Invalid response: %s.' % str(resp.status) raise FlowExchangeError(error_msg)
def step2_exchange(self, code, http=None): """Exhanges a code for OAuth2Credentials. Args: code: string or dict, either the code as a string, or a dictionary of the query parameters to the redirect_uri, which contains the code. http: httplib2.Http, optional http instance to use to do the fetch Returns: An OAuth2Credentials object that can be used to authorize requests. Raises: FlowExchangeError if a problem occured exchanging the code for a refresh_token. """ if not (isinstance(code, str) or isinstance(code, unicode)): if 'code' not in code: if 'error' in code: error_msg = code['error'] else: error_msg = 'No code was supplied in the query parameters.' raise FlowExchangeError(error_msg) else: code = code['code'] body = urllib.urlencode({ 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': self.redirect_uri, }) headers = { 'content-type': 'application/x-www-form-urlencoded', } if self.user_agent is not None: headers['user-agent'] = self.user_agent if http is None: http = httplib2.Http() http.add_credentials(self.client_id, self.client_secret) resp, content = http.request(self.token_uri, method='POST', body=body, headers=headers) d = _parse_exchange_token_response(content) if resp.status == 200 and 'access_token' in d: access_token = d['access_token'] refresh_token = d.get('refresh_token', None) token_expiry = None if 'expires_in' in d: token_expiry = datetime.datetime.utcnow() + datetime.timedelta( seconds=int(d['expires_in'])) if 'id_token' in d: d['id_token'] = _extract_id_token(d['id_token']) logger.info('Successfully retrieved access token') return OAuth2Credentials(access_token, self.client_id, self.client_secret, refresh_token, token_expiry, self.token_uri, self.user_agent, revoke_uri=self.revoke_uri, id_token=d.get('id_token', None), token_response=d) else: logger.info('Failed to retrieve access token: %s' % content) if 'error' in d: # you never know what those providers got to say error_msg = unicode(d['error']) else: error_msg = 'Invalid response: %s.' % str(resp.status) raise FlowExchangeError(error_msg)